Copyright: Copyright 1993 Microsoft Corp.


 16-bit Windows SDK Knowledge Base

Prepared 06/28/95

 GDI Articles

 Kernel Articles

 Networking Articles

 Tools Articles

 User Articles

 Bug Articles

 Samples

THE INFORMATION IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES EITHER EXPRESSED OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS, OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FORGOING EXCLUSION OR LIMITATION MAY NOT APPLY.


GDI Articles
 16-bit Windows SDK Knowledge Base

 GDI Articles

 Definition of a Region

 GDI Simulation Routines and Device Drivers for Windows

 A Discussion of Windows Fonts

 CreatePen() and CreatePenIndirect() Use Predefined Styles

 Printer Page Area in Windows

 Restoring Objects in a Metafile DC

 Using a Different Hardware Font Instead of the Default

 Windows DEVICEDATA Escape Usage

 Information About Clipping, GetDeviceCaps() and GDI

 Print Manager Print Job File Limit and WM_SPOOLERSTATUS

 PRB: PlayMetaFile() Not as Fast as More Complex Technique

 Drawing a Different Icon for Each Application Instance

 Font Metrics and the Use of Negative lfHeight

 Expanded BANDINFO Documentation

 The Four Classes of Device Banding

 PRB: Some Windows GDI Functions Fail on Banding Printers

 Windows SDK: Limit of Logical Coordinate System in Windows

 EndPage(), NEXTBAND, and NEWFRAME Reset DC Attributes

 GETPHYSPAGESIZE Landscape vs. Portrait Mode

 Changing Printer Parameters from an Application

 Changing the Palette of Colors on a Nonpalette Device

 wsprintf() %s Parameters Not Cast to LPSTR

 Using SetDIBitsToDevice() with a Memory Device Context

 Windows Metafile Functions & Aldus Placeable Metafiles

 Playing a Metafile into Another Metafile in Windows

 Using a Fixed-Pitch Font as the System Default

 Windows 3.x Metafiles Support DeleteObject()

 Performance Differences Between LineTo() and Polyline()

 Obtaining Support for Adobe Type Manager (ATM)

 PRB: SDK Sample Applications Use Incorrect Background Brush

 ExtTextOut() Instead of TextOut() to Improve Performance

 Font Rotation Under Microsoft Windows

 Baseline Shifts in Cell When Character Italicized

 Banding, Printing, and the Number of Bands

 Icon and Cursor Size Determined by Display Driver

 Logical and Physical Coordinate Relationship

 Microsoft Windows Caches Five Display Contexts

 Charts and Graphs for Windows-Based Applications

 Using GetDIBits()

 Supporting PostScript Features in Windows

 Steps to Send a Document to a Printer

 PRB: Available Memory Decreases When Print Job Terminated

 Windows, Code Pages, and Character Sets

 Basics of Banding Printing in Windows

 Paper Sizes 50 through 56 Reserved for PostScript Driver

 How to Create Device-Independent Printing Code

 Verifying the Printer Connection

 Using ExtDeviceMode() with DM_COPY

 PRB: Complex Printing Region Printed Incorrectly

 Detecting EGA.SYS

 Drawing Transparent Bitmaps

 Converting Between Device-Dependent Bitmaps and DIBs

 Discussion of Metafiles

 DeviceCapabilities(DC_BINNAMES) Data Format

 PRB: "Orphan" Metafiles Not Tracked by Debugging Windows

 CopyMetaFile() Creates Incorrectly Sized Destination

 PRB: PrintDlg() Returns PDERR_NODEVICES w/ HP DeskJet

 PRB: GDI Functions Do Not Affect Printer Device Context

 PRB: Loading Metafile Causes "Cannot Convert Picture" Error

 Technical Details of TrueType Fonts in Software Library

 PRB: Petzold's COLORS1 Sample Application Consumes Resources

 PRB: IBM Proprinter Draft Mode Unavailable Under Windows 3.1

 Windows TrueType Fonts Reading List

 Causes for Failure of DC-Creation Functions

 PRB: Colors Lost Printing Color Metafile on Color Printer

 Reasons for Failure of Bitmap Functions

 PRB: How to Work Around WMFDCODE 64K Limitation

 PRB: MULTIPAD Sample from Win 3.1 SDK Gives Printing Error

 Using GetCharABCWidths() to Calculate Text Extents

 Managing Icons Extracted Using ExtractIcon()

 Utilizing High Color Resolution Devices

 PRB: Metafiles and Palettes

 Increasing the Transmission Retry Timeout for Printing

 Enabling and Disabling Print Manager

 Diagnosing Printing Problems in Your Application

 Reading and Writing Icons from ExtractIcon

 Nesting Scalable Metafiles

 Getting/Setting the Default Printer from Windows

 An Alternative to SpoolFile()

 How GDI Sends Data to the Printer

 Calculating MM_HIMETRIC Units for the METAFILEPICT

 PRB: dmPrintQuality Does Not Affect Text Print Quality

 PRB: GDI Heap Fills Up While Playing a Metafile

 PRB: Creating Many Fonts Causes a GPF in Windows 3.1

 How to Print a Single Line Without Formfeed

 PRB: Polyline Fails with NULL Clipping Region

 Kernel Articles

 Networking Articles

 Tools Articles

 User Articles

 Bug Articles

 Samples


Kernel Articles
 16-bit Windows SDK Knowledge Base

 GDI Articles

 Kernel Articles

 Locking Discardable Objects

 Heap and Stack Usage Within Windows

 Windows: Nonpreemptive vs. Preemptive Scheduling

 Reference Counts for Windows Dynamic Libraries

 Definition of Different Types of Libraries in Windows

 The Purpose of WINSTUB in Windows SDK

 How to Transparently Intercept Procedure Calls in Windows

 How to Get a Pointer to the Stack

 How Windows Resolves Far Calls When Movable Flag Is Used

 Windows File I/O vs. C Run-time File I/O

 Fatal Error Messages 0x0140 and 0x0240

 Shrinking Heap Space

 How a DLL Can Display a Message Using MessageBox()

 Windows Does Not Implement INT 15H to Handle Multitasking

 Windows Does Not Support Real-Time Programming

 When Can a Call to GlobalLock() Fail?

 ValidateFreeSpaces(), GlobalCompact(), and Wild Pointers

 PRB: Windows FatalExit 0x0280 Error Caused by FAR WinMain

 Calculating Memory Requirements for MS-DOS-Based Apps

 Applications and the Math Coprocessor Under Windows

 Using OpenFile() with Sharing and Inheritance Bits

 Using GlobalFlags() to Test for GMEM_DISCARDABLE

 How Windows Updates the LRU (Least Recently Used) List

 PRB: File Handles Cannot Be Shared Between Programs or DLLs

 Demand Paging MS-DOS-Based Applications

 PRB: GlobalUnlock() Can Cause Fatal Exit 0x02F0

 Failure to Load Resources When All File Handles Are Used

 Requested Contents for Windows Problem Reports

 EMS Support in Windows Versions 3.0 and 3.1

 Do Not Use the MS-DOS APPEND Utility in Windows

 Global Lock Count Changes in Windows 3.x

 Why GlobalAlloc() Returns a Handle to a 0-Byte Segment

 DPMI Specification Available from Intel

 Overview of How to Share Memory Between Applications

 Windows Int 21h and NetBIOS Support for DPMI

 C Run-time Functions Can Use Far Pointers in Medium Model

 PRB: Fatal Exit Code 0x0019 Definition and Causes

 How to Determine When Another Application Has Finished

 Access to the Windows Clipboard by MS-DOS-Based App

 File Manager's Mechanism for Sensing File System Changes

 Creating a Single Import Library for Multiple DLLs

 PRB: Cannot Exit Windows with DLL-Instanced Windows Open

 Creating Dynamic-Linked Libraries Without Data Segments

 Profiling Time Between OutputDebugString and FatalExit

 Updating Cached Private Profiles (.INI Files)

 Handling Critical Errors in Windows-Based Application

 Avoid Low-Level Operations in Windows Programs: Use DLLs

 PRB: Activating Full-Screen DOS App from Icon in Enhanced Mode

 Using Variable Argument Lists in DLL Functions

 PRB: GetModuleHandle() and Long Path Causes UAE

 Drive and Directory Manipulation in Windows

 Maximizing the Use of Available Memory in Windows

 Retrieving the Filename of an Application or DLL

 Shorthand Notation for Memory Allocation Flags

 Determining That SHARE Is Loaded Under Microsoft Windows

 WINMEM32 Not Version Dependent

 MS-DOS-Based Application Characteristics Under Windows

 Allocation Limit on WINMEM32 Global32Alloc() Function

 Appropriate Uses of WINMEM32

 Ownership of Global Memory Allocated by a DLL

 Minimizing Lock and Unlock Calls in Protected Mode

 Some Windows Functions Cannot Be Called from LibMain

 Three Methods to Import Functions from a DLL

 PRB: Fatal Exit 0x00FF or 0xD000: MakeProcInstance Fails

 Steady Timer Messages in a Dynamic-Link Library (DLL)

 Opening Files, Compatibility Mode and Windows

 Using Memory Below 1 Megabyte

 Using a TSR to Share XMS Memory Between Virtual Machines

 How to Start a Windows-Based App Directly from MS-DOS

 Sharing Windows-Based Applications Across Networks

 Keeping MS-DOS-Based App Active Under Windows 3.1

 Determining Free Memory in Windows Enhanced Mode

 Passing File Handles from TSR to Windows-Based App

 Determining Windows Version, Mode from MS-DOS App

 PRB: One Cause of Fatal Exit 0x0140 "Local Heap Is Busy"

 Techniques to Find Extended Memory in a Windows DLL

 PRB: One Cause of Fatal Exit 0x001A

 Determining What Mode and Version of Windows Is Running

 Using TOOLHELP to Determine Free System Resources

 Determining Which COM Ports Are Present in Enhanced Mode

 Full-Screen MS-DOS Apps Slow Timer Msgs in Enhanced Mode

 PRB: Global TSR Pop-ups Incompatible with Windows

 General Information Regarding Dynamic-Link Libraries

 PRB: LoadLibrary() Returns Error 6

 PRB: Reset A20 Bit Set During DPMI Simulate Interrupt Crash

 Differences Between Task Handles and Instance Handles

 Properly Using Dynamic-Link Libraries

 Memory Access Methods for Protected Mode Applications

 Considerations for Programming DATA NONE DLLs

 Rules for Using Far Pointers to Memory Objects

 Using _export Keyword or DEF File EXPORTS Statement

 Real Mode Not Supported by Windows 3.1

 Retrieving MS-DOS Environment Vars from a Windows DLL

 Using Huge Pointers with Blocks of Memory Larger Than 64K

 Retrieving the Names of Simultaneous Tasks Under Windows

 Determining the Version of MS-DOS from a Windows App

 Modules, Instances, and Tasks

 PRB: Segment Was Discardable Under 3.0 Notification

 Limits on the Number of Open Files

 Hooking Interrupt 21h Before Windows

 Windows 3.1 Standard Mode and the VCPI

 XMS Calls Under Windows 3.1

 Retrieving Application Exit Code in MS-DOS Window

 PRB: XMS Version Information in MS-DOS Window Incorrect

 Memory Use Limitations in Microsoft Windows

 PRB: DLL Function Returns Float or Double Value Incorrectly

 PRB: Avoiding "Insufficient Memory to Run" Errors

 Redirecting Debugging Information Under Windows 3.0, 3.1

 No MS-DOS Extended Error Info for Windows File Functions

 PRB: Creating File with Exclusive Access Allows Concurrent Use

 Creating Import Libraries with the __export Modifier

 Stack Traces Under Windows 3.1 SDK Debugging Kernel

 Creating Dynamic Code Segments Using PrestoChangoSelector

 Additional Documentation for GetDOSEnvironment()

 Using Large Memory Model, Microsoft C/C++, & Windows 3.1

 Using OpenDriver() to Communicate Data to Installable Drv

 Terminating Windows-Based Application from Another App

 GlobalReAlloc() and GMEM_ZEROINIT Clarified

 Calling Int86?, Intdos?, and DOS3Call() from Windows

 Virtual DMA Services (VDS) Application Note Available

 Using GlobalDosAlloc() and GlobalDosFree()

 Detecting Idle Time in Windows

 Registering a Class in a DLL

 PRB: Error in the THSAMPLE Sample Application

 Chaining NotifyRegister Callbacks Issuing Notifications

 PRB: Using SetCommState() to Toggle DTR/RTS for Flow Control

 Accessing the Modem Status Register (MSR) in Windows

 The DCB Structure in Windows 3.1

 Sharing Files with Windows for Workgroups Clients

 The "Segment Load Failure" Error Message

 WEP and Link Error L2023 Export Imported

 Callback Functions in Multiple Instance Applications

 PRB: Passing Modified Environments to Child Processes

 Use EV_RINGTE for Modem Ring Detection

 SetSelectorLimit() Crossing 1 Megabyte Boundary

 How OF_SHARE Modes Affect Opening Files

 Using Int 21h Get/Set Media ID in the Windows Environment

 Explanation of Exporting Functions in Windows

 PRB: KRNL386: Unable to Enter Protected Mode

 Solving the "Insufficient Memory to Run" Situation

 How to Determine Drive Types in Windows

 Determining the Stack Size of an Application

 PRB: Not Enough Space for Environment

 Using DebugOutput to Debug a Windows-Based Application

 "Backward Compatibility Hack Enabled" Warning

 PRB: Share Buffer Exceeded

 Using More Than Four Communications Ports in Windows

 Setting Baud Rates in Windows 3.1

 Suppressing "Cannot Find MYDLL.DLL" Error Box

 GETBASEIRQ EscapeCommFunction()

 WEPs, Windows, and Microsoft Visual C/C++ Compilers

 Intel Privileged and Sensitive Instructions

 How to Move Data Between Large Overlapping Buffers

 Using WM_COMMNOTIFY in an MFC Application

 Transmitting a BREAK Signal

 PC Hangs While Running a Communications Application

 Determining System Version from a Windows-Based Application

 How to Access Physical Memory in 16-bit Windows-Based Apps

 Networking Articles

 Tools Articles

 User Articles

 Bug Articles

 Samples


Networking Articles
 16-bit Windows SDK Knowledge Base

 GDI Articles

 Kernel Articles

 Networking Articles

 Using NetBIOS Interrupts Under Windows

 Developing Network Applications for Windows

 The Windows 3.10 Developer's Notes

 Windows APPC for 16 and 32-Bit Windows

 Windows CPI-C API for 16 and 32-Bit Windows

 Windows CSV API for 16 and 32-Bit Windows

 Windows LUA API for 16 and 32-Bit Windows

 How to Use WNetGetUser() in Windows for Workgroups

 How to Determine Whether Windows for Workgroups is Running

 Windows for Workgroups SDK

 PRB: Error 6 RPC_S_PROTSEQ_NOT_SUPPORTED in 16-bit Application

 How to Perform Programmatic Logon from Windows for Workgroups

 NetUserPasswordSet Uses NERR_PasswordTooShort for Other Things

 MS-DOS-Based RPC Application Cannot Use TCP/IP

 Tools Articles

 User Articles

 Bug Articles

 Samples


Tools Articles
 16-bit Windows SDK Knowledge Base

 GDI Articles

 Kernel Articles

 Networking Articles

 Tools Articles

 Format for Strings and Longs in RCDATA in RC

 Meanings of Resource Compiler Messages

 PRB: Error L2028: Automatic Data Segment Plus Heap Exceed 64K

 Executable Modules Must Be Processed by Resource Compiler

 PRB: RCPP.EXE Error: Compiler Limit: Macro Expansion Too Big

 Using the Linker /ALIGN Option

 Developing Common Code for Both Windows and Macintosh

 WDEB386 Debugger's Use of COM Port

 PRB: Encountering an INT 01 with WDEB386

 PRB: C Pragma Comment & #ident Strings Missing from Executable

 Windows-Based Application Installation Sample Code

 Help Compiler Internal Error Possible Causes

 Windows SDK Support for Microsoft FORTRAN Compilers

 Windows Programmer's Reference (Advisor Format)

 Windows Help (HLP) File Format Is Not Available

 Overcoming "C4071 No Function Prototype Given" Warning

 Corrupt RES File May Crash Dialog Editor

 PRB: SPY Updates Only One Line with Small Buffer

 PRB: Resource Compiler Error RW1022 Caused by Temporary File

 WIN.INI Settings for Windows Help Hypertext Colors

 Information About Headings and Labels in HEAPWALK

 PRB: RC Error RW1031: Segment Too Large for Load Optimization

 "Profiler VM Terminated Abnormally" Message Causes

 PRB: Application Not Recognized as Compatible with Windows 3.x

 Advanced WDEB386 Features and Tips

 PRB: "Export Not Defined" Linker Message

 Implicit Casting by C Compiler Can Cause Problems

 Using Near and Far Pointers with C Run-Time Functions

 Rich Text Format Subset Supported by Windows Help

 Tips on Installing WDEB386

 Creating a Nonscrollable Region in Windows Help 3.1

 PRB: Resource Compiler Cannot Find Include Files

 PRB: Value of hPrevInstance Incorrect

 PRB: Problems with Dr. Watson or with the Packager

 Correctly Configuring PWB for Windows Development

 PRB: Causes of Help Compiler "Table Too Complex" Warning

 Swap Tool Not Included with Windows SDK 3.1

 Debugging GP Faults with WDEB386

 PRB: Help Compiler Warning "Using Old Key Phrase Table" Cause

 Help Does Not Support Side-by-Side Paragraphs

 PRB: Combining Multiple Compiled Resource Files Fails

 Windows 3.1 Application Compatibility (part 1 of 7)

 Windows 3.1 Application Compatibility (part 2 of 7)

 Windows 3.1 Application Compatibility (part 3 of 7)

 Windows 3.1 Application Compatibility (part 4 of 7)

 Windows 3.1 Application Compatibility (part 5 of 7)

 Windows 3.1 Application Compatibility (part 6 of 7)

 Compatibility Test For Windows 3.1 Checklist

 An Annotated Dr. Watson Log File

 PRB: Two Builds of Same Windows Help File Not Identical

 Introduction to STRICT and Message Crackers

 PRB: Binding Resources to Executable Increases File Size

 SPY Utility Reports Application Name, Not Module Name

 PRB: Borland Turbo Debugger Cannot Load WINDEBUG.DLL

 Use Extended Memory to Build Larger Windows Help Files

 Application Cannot Clear the Windows Help History List

 Setup Toolkit for Windows Compatible with Windows 3.0

 Windows Help and Help Compiler Capacity Limits

 Sources of Information about the Windows Help Compiler

 PRB: "Unrecognized Linker Switch /NOP" Linking Setup Toolkit

 WDEB386-Compatible Timing Card Available

 Porting Windows Help Source Files from Version 3.0 to 3.1

 Windows Help Print Macro Does Not Print Pop-up Contents

 Cannot Destroy Default Windows Help Menus and Buttons

 PRB: Bitmap Causes Windows Help Compiler Out-of-Memory Error

 Using LINK 5.3 to Create Applications for Real Mode

 PRB: Building Setup Toolkit Overwrites DIALOGS.RES File

 Packing List: Windows 3.1 SDK Part 1 (3.5-Inch Disks)

 PRB: Small Caps Text Unchanged in Windows Help

 Using the Microsoft Windows Help Compiler

 How to Maximize Setup Toolkit Window

 Details of Setup Toolkit Function GetCopyListCost()

 The Microsoft Setup Toolkit for Windows -- A Tutorial

 Using Both the Retail and Debug Kernel of Windows

 Causes of Help Compiler Error 5059

 .SHG Files Cannot Be Edited

 DBWIN Won't Work with Text on First Line of Mono Display

 Windows Setup Toolkit Tutorial Available for Download

 DOCERR: Minimal SDK Profiler Functions Required

 PRB: _MSSETUP.EXE Disappears

 Creating Help Files Compatible with Windows 3.0 and 3.1

 Works for Windows Cannot Be Used to Author Help Files

 MASM 6.0 Windows Programming Sample

 PRB: Setup Toolkit's SETUP.EXE Does Not Launch Windows

 Using the Setup Toolkit Function StampResource()

 PRB: DBWIN Sample Application May Appear to Hang Windows

 Windows Help Internal Variables

 Help Topic Margins Always 1 Inch When Printed

 New SHED.EXE Preserves Hot Spot Information

 Using Functions and Subroutines with Microsoft Setup

 Linking Windows-Based Applications and DLLs with /NOI

 Compatibility Issues for Microsoft Windows Versions 3.x

 PRB: LINK Error L2022: Export Undefined

 PRB: Starting Heap Walker Results in a GP Fault

 PRB: Combined Windows 3.0 and 3.1 Applications

 PRB: MASM Code Using CMACROS.INC Does Not Build Correctly

 PRB: Help Compiler Causes Fatal Exit or Other System Failure

 Using the "BR" Command in WDEB386.EXE

 Win32 Resource Localization Tools Available

 The Unexpected QuickWin Error

 Reasons for Failure of SetRestartDir

 PRB: Setup Toolkit DoMsgBox Shows Wrong Buttons or Icons

 PRB: Setup Toolkit Error "Parser out of memory"

 Using the Setup Toolkit's GetLocalHardDrivesList Function

 PRB: Setup Toolkit Cancel Button Not Working On Disk Changes

 Running WINHELP.EXE with Command Line Switches

 Installing and Using the Debugging Version of Windows

 Microsoft Development Library Demo Available in

 PRB: Heap Walker's Object: USER LocalWalk Doesn't Track Data

 User Articles

 Bug Articles

 Samples


User Articles
 16-bit Windows SDK Knowledge Base

 GDI Articles

 Kernel Articles

 Networking Articles

 Tools Articles

 User Articles

 Window Handles of Global Objects

 Using EndPaint() and BeginPaint()

 Changing the Name of a Second Instance of an Application

 Changing Window Colors with Control Panel

 Windows Resource Numbering Starts at 1

 How to Change a Window's Parent

 More Information About Atoms

 Split Scrolling Using Two Windows

 Return Value from ChangeClipboardChain()

 Scope of Window Classes

 PRB: Window Dragged Close to Screen Edge Becomes Invisible

 Changing the Mouse Cursor for a Window

 Using the WM_CTLCOLOR Message

 Obtaining an Application's Instance Handle

 Differences Between PostAppMessage and PostMessage Funcs

 Active Application, Active Window, Input Focus Definition

 Algorithm Creates Window Same Size As Full-Screen Window

 Performing Background Processing Without Using Timers

 When PostMessage() Will Return 0, Indicating Failure

 DlgDirSelect() Has Undocumented Behavior

 Limit to the Number of Characters Stored in a List Box

 Communicating Between Windows Virtual Machines with DDE

 FatalExit 0x0001 Possible If WM_CTLCOLOR Used Improperly

 General Information About Windows WM_TIMER Messages

 Calculating Free System Resources in Microsoft Windows

 Do Not Call Message Boxes Via Radio Buttons

 Windows Message-Processing Caveats

 Using WriteProfileString to Delete WIN.INI Entries

 Executable-File Header Format

 Font-File Format

 Aligning Columns in a Windows 3.x List Box

 Possible Causes for System Resource Reduction

 Dialog Box Creation Fails If Text Starts w/ Character 255

 Inserting Right Justified Text in a Menu in Windows

 Using Window Extra Bytes in Custom Controls

 How to Respond When DDE Data Cannot Be Locked

 List Box and Combo Box Capacity Limits

 Control Panel Doesn't Respond to WM_WININICHANGE Messages

 Avoid SetClassLong If Subclassing a Standard Control Class

 How to Give a 3-D Effect to Windows Controls

 Fatal Exit Code 0x0506 Definition

 Sources of Information Regarding Windows DDE

 Reactivating First (and Only) Instance of an Application

 PRB: SDK Sample Programs Define Delete Accelerator Incorrectly

 Tracking Down Lost System Resources

 Menus Supported in Dialog Boxes w/o DS_MODALFRAME Style

 Keeping a Window on Top of All Other Windows

 Preventing an MDI Child Window from Changing Size

 Context-Sensitive Help in a Dialog Box Through F1

 Changing the Color of an Edit Control

 Freeing Resources Used by a Multiline Edit Control

 Size Limits for a Multiline Edit Control

 Actions Prohibited in System Modal Dialog Boxes

 Killing the Parent of a Modal Dialog Box

 Designing Applications for High Screen Resolutions

 "Power-Friendly" Applications

 Drawing the Icon for a Minimized Application

 Private Profile (INI) Files Not Designed as Database

 When to Use WIN.INI or a Private INI File

 Adding Items to the System Menus of All Applications

 Using PeekMessage() Loops in a Dialog Box

 Working Around the STRINGTABLE 255 Character Limit

 DBCS Support in Windows Versions 3.0 And 3.1

 Program Manager Restrictions Settings

 Tips for Writing DBCS-Compatible Applications

 Altering Edit Control Strings in Place May Cause UAE

 Ending the Windows Session from an Application

 XLTABLE Clipboard Format Documentation Available

 Guidelines for Allocating Instance (Per-Window) Data

 Creating a Progress Dialog with a Cancel Option

 Different Ways to Close an Application Under Windows

 Retrieve Line Number from Edit Control Sample Code

 Modifying the System Menu of an MDI Child Window

 Introduction to Nonpreemptive Multitasking in Windows

 Overcoming the 64 Kilobyte Limit for List Box Data

 Subclassing the Desktop and Windows of Other Applications

 Windows Paintbrush File Format

 PRB: BS_GROUPBOX-Style Child Window Background Painting Wrong

 Save System Resources with One Control per Control Class

 Terminating the Creation of an MDI Child Window

 Possible Causes of Dialog Box Creation Failure

 Microsoft Drag-Drop Server Strategy

 WH_CALLWNDPROC, WH_GETMESSAGE Hooks Sample Code

 DDEML CONVINFO Structure, wConvst Field Description

 Timers and Timing in Microsoft Windows

 WM_CTLCOLOR Processing for Combo Boxes of all Styles

 Creating Applications that Task Manager Does Not Tile

 Using the WM_GETDLGCODE Message

 Extended Characters Different Under Windows

 Implementing the Drag-Drop Protocol

 CONVINFO Data Structure wStatus Field Description

 PRB: Vertical Bars Displayed in Message Box, Control Text

 Multiple Document Interface Enhancements in Windows 3.1

 ODVHLB Demonstrates Owner-Draw Variable-Height List Box

 Program Manager DDE Command AddItem Documentation

 PRB: Crash Double-Clicking File in Open or Save Common Dialog

 PRB: DLL System Hook Function Not Affecting Apps System-Wide

 WM_PAINTICON Message Removed from Windows SDK Docs

 Software Library Has DDE Management Library Information

 Buttons and Cursors Documentation and Sample

 Both Windows in SetParent() Call Must Belong to Same Task

 PRB: Common Dialog Box Hook Function Cannot Access Variables

 Handling WM_QUIT While Not in Primary GetMessage() Loop

 PRB: Accented Characters in Filename Controls Lose Accents

 Is DdePostAdvise Synchronous?

 Setting the CAPS LOCK, SCROLL LOCK, and NUM LOCK States

 PRB: DdeInitialize Fails in Implicitly-Loaded DLL's LibMain()

 PRB: Double-Click Does Not Close Win 3.1 Maximized MDI Child

 Detecting Whether a Menu Is Open

 PRB: MAKEFILE for HOOKS Sample Implemented Incorrectly

 Adding 3D Controls Using CTL3D.DLL

 PRB: Using HSZ in AFXEXT.H and DDEML.H

 PRB: Using ToAscii() in Journal Record Hooks

 Windows 3.1 Card File Format

 How to Use Network DDE

 .PIF File Format Unavailable

 Changes Between Win 3.1 and WFW 3.1 Versions of DDEML

 Obtaining Group/Item Info from ProgMan Using DDEML

 Using the ShowGroup() Command in Program Manager

 Using ReplaceItem() Command in Program Manager DDE

 EM_SETSEL wParam Not Used in Single Line Edit Controls

 PRB: Min/Max Boxes Do Not Work with DS_MODALFRAME

 Dynamic Data Exchange Interface for Replacement Shells

 Types of System Modal Message Boxes

 How to Detect Mouse and Mouse Port

 Updating Multiple Device= Lines in SYSTEM.INI

 DdeCreateDataHandle() Memory Allocation Granularity DDEML

 Top 10 DDEML Support Issues

 Graying Text in Disabled Multiline Edit Controls

 PRB: Windows 3.1 SDK HOOKS Sample Causes a GP Fault

 PRB: GetVersion Returns 3.10 from Windows for Workgroups 3.11

 PRB: Caret Appears Outside Border in Multiline Edit Control

 Bug Articles

 Samples


Bug Articles
 16-bit Windows SDK Knowledge Base

 GDI Articles

 Kernel Articles

 Networking Articles

 Tools Articles

 User Articles

 Bug Articles

 BUG: No WM_SETFONT to Custom Controls

 BUG: RC Error RW1008 If NULL Entry in PATH

 BUG: Complex Graphics Image Partially Printed

 BUG: FatalExit() Interacts Through Terminal Only

 BUG: MapVirtualKey() Maps Keypad Keys Incorrectly

 BUG: Crash with frexp() in Small or Medium Model DLL

 BUG: Combo Boxes in DS_SYSMODAL Dialog Boxes

 BUG: PostScript Driver Version 3.4 Returns Incorrect Page Size

 BUG: Protected-Mode GlobalCompact() Return Not Free Memory

 BUG: Text Formatting Lost When Edit Text Dialog Box Used

 BUG: Common Dialog GP-Fault on ESC Key with Mouse Button Down

 BUG: GlobalPageLock() Moves Memory Fixed by GlobalFix()

 BUG: GetModuleFileName() Returns Relative File Path

 BUG: System Menu Wrong for CS_NOCLOSE-Style MDI Child

 BUG: Buttons Painted Incorrectly After Color Changed

 BUG: SETCOLORTABLE Escape Disables Dithering

 BUG: GetGlyphOutline() Returns Blank Bitmap

 BUG: Input Focus Lost When Control Returns From Windows Help

 BUG: LIBENTRY.ASM Missing Include File Error

 BUG: MDI More Windows Dialog Activates Wrong Child

 BUG: PrintForm() Does Not Print Ink from Control

 BUG: Dsklayt2 /W Option Without Disk Number Fails

 BUG: Dictionary Receives No DIRQ_SYMBOLGRAPH Message

 BUG: Help Compiler Hangs When .HPJ File [MAP] Section Too Big

 BUG: OpenFile() API Fails on Novell Temp Drive

 BUG: HPPCL Driver Reports SETABORTPROC Not Supported

 BUG: Color PostScript Drivers Report Incorrect Data

 BUG: GetGlyphOutline() Returns Partial Glyph

 BUG: Scrolling DIB DC Fails

 BUG: Setup CreateProgmanItem Does Not Overwrite Item

 BUG: BitBlt() Bitmap on VGA Display Causes GP Fault

 BUG: HC Error 2050 from #include in Help Project File (.HPJ)

 BUG: No Dr. Watson Log File in Drive's Root Directory

 BUG: Minimized Windows Help Yields Incorrect Icon

 BUG: Complex Clipping Region Might Cause UAE/GP Fault

 BUG: Cannot Map TT Font to Same Name PostScript Device Font

 BUG: CreatePatternBrush() with Large Bitmap GP Fault

 BUG: Superclassed Scroll Bar's Parent Not Sent WM_CTLCOLOR Msg

 BUG: ProgMan DDE Reload() Command Does Not Work Properly

 BUG: PostScript Handles lfItalic Field Incorrectly

 BUG: Graphics Operations Consume GDI Memory

 BUG: ETO_CLIPPED Does Not Clip Rotated Text

 BUG: Application Errors From Long Text in the Dialog Editor

 BUG: RC /fe Switch Does Not Work

 BUG: UngetCommChar() Causes Character Loss or GP Faults

 BUG: StretchDIBits() Prints Wrong Part of DIB with PSCRIPT.DRV

 BUG: OpenFile() Fails When UNC Name Longer Than 11 Characters

 BUG: Extra CN_RECEIVE/CN_TRANSMIT Events

 BUG: DDESPY GP Faults Upon Return of CBR_BLOCK

 BUG: AddAtom Causes Divide by Zero Error

 BUG: EV_RLSDS Event Does Not Indicate Current RLSD State

 BUG: Iconic MDI Application Titles Do Not Update Properly

 BUG: SetDIBitsToDevice Faults on 24-BPP PM-Style DIBs

 BUG: StretchDIBits Faults on 24-BPP PM-Style DIBs

 BUG: PALETTEINDEX Not Working for Thin Lines on HP PaintJet

 BUG: SelectClipRgn() Does Not Update Properly on Printer

 BUG: SetPixel() Doesn't Work Properly on a PS Printer

 BUG: System-Wide WH_DEBUG Hook Causes a GP Fault

 BUG: Resolutions for DBWIN Utility Continuous Beeping

 BUG: GP Fault in LoadLibrary() with C++ DLL

 BUG: Problem with DrawText Statement

 BUG: Palettes Realized in a Memory DC May Corrupt Screen

 BUG: SystemParametersInfo() Does Not Modify WIN.INI

 BUG: DDEML Fails to Free Item Name HSZ on a LATEACK

 BUG: Ampersand in Menu Item Is Not Converted

 BUG: MoveTo/LineTo Causes Divide by 0 Error

 BUG: Gaps Between Wedges Drawn with Pie()

 BUG: DDE Warning Message: Invalid Value: -32767

 BUG: Nonscrolling Region in Help File Topic Does Scroll

 BUG: Size of Owner-Draw Drop-Down Combo Box in Dialog Is Wrong

 BUG: SetWindowPos() on an Iconic Window and its Caption

 BUG: R2_XORPEN Binary ROP Code Ignored for Wide Pens

 BUG: Pie() and Arc() Functions Fail with a Wide Pen

 BUG: Vector Font Rotation Skewed with Non-Top-Left Alignment

 BUG: Text Truncated in Edit Control

 BUG: LineTo() Endcaps Misaligned with Large Pen Width

 BUG: Rotated TrueType Font Repaints Many Times

 BUG: Some ROP Codes Cause Inconsistent Polygon() Line Segments

 BUG: Pie() Vertex Not Drawn Completely with Wide Pen

 BUG: Arc() Not Drawn Completely with a Wide Pen

 BUG: Occasional Gap Between Adjacent Pie() Wedges

 BUG: GetRasterizerCaps Returns Zero When TrueType Is Disabled

 BUG: _lread() Functions Incorrectly When No Floppy in Drive

 BUG: OpenFile() Doesn't Handle Forward Slash ("/") Character

 BUG: Brush Misaligned in PaintRgn()

 BUG: Some TrueType Character Pairs Run Together on VGA

 BUG: IsBadStringPtr() Reports Bad String as Valid

 BUG: DeleteObject() Generates Debug Errors in WEP

 BUG: DPMI Function 0203h Does Not Report Error

 BUG: Dr. Watson Fails to Write Log File

 BUG: Debug Kernel Ignores Fatal Exits When OutputTo=

 BUG: Opaque Rectangle Too Small on Rotated TrueType Fonts

 BUG: Character Background Is Not Painted Correctly

 BUG: Polygons Drawn with Pens of Odd Width (> 5) Misalign

 BUG: Misleading Default Pushbutton Painting

 BUG: GetPrivateProfileInt() May Not Read Correct Value

 BUG: GlobalCompact() May Return an Inaccurate Value

 BUG: Explicitly Loaded Modules Not Removed from Memory

 BUG: LoadResource() GP Faults When Passed an Invalid HRSRC

 BUG: ROP2 Code Applied Incorrectly in Pie() Function

 BUG: LB_SETTOPINDEX Doesn't Conform to Documentation

 BUG: EM_CANUNDO Returns Zero After EM_REPLACESEL

 BUG: Left Part of Character Is Clipped with ExtTextOut/TextOut

 BUG: DrawFocusRect Fails in MM_LOMETRIC or MM_ISOTROPIC Mode

 BUG: GetGlyphOutline() with GGO_BITMAP Fails with Large Scale

 BUG: Edit Controls and WS_CLIPCHILDREN Function Differently

 BUG: Printer Driver Receives "bigfonts" When Not Supported

 BUG: StretchDIBits Not Correctly Stretching RLE DIBs w/ Jumps

 BUG: StretchBlt() Does Not Perform Palette Translations

 BUG: TabbedTextOut() in Metric Mapping Mode Incorrect

 BUG: Driver vs. GDI-Simulated Styled Lines Don't Match

 BUG: GP Fault When Drawing on a Memory-Based DC

 BUG: StretchBlt()/StretchDIBits() Fail with Very Large Stretch

 BUG: Outline of a Pie() Slice May Not Be Completely Smooth

 BUG: GetTimerResolution not in LIBW.LIB

 BUG: General Protection Fault When Accessing an HFONT

 BUG: DDESPY and Ctrl Key Cause GP Fault in Windows NT

 BUG: Caching GDI Objects Causes Temporary GDI Resource Leak

 BUG: MCIWndClass Popup Window Palette Flashes

 BUG: GetOutlineTextMetrics() Returns Bad Data in Japanese Win

 BUG: True Type Font Display Problem with WINHELP ver 3.10.151

 BUG: WinG 1.0 Bug List

 BUG: ExtractIcon Not Freeing Up Memory

 BUG: EM_LIMITTEXT Causes GPF in Japanese and Chinese Windows

 BUG: Winsock--Lost FD_WRITE Notifications

 Samples


Samples
 16-bit Windows SDK Knowledge Base

 GDI Articles

 Kernel Articles

 Networking Articles

 Tools Articles

 User Articles

 Bug Articles

 Samples

 SAMPLE: Using DLLs to Share Menus and Other Resources

 SAMPLE: App Demonstrates Modal and Modeless Dialog Boxes

 SAMPLE: Demonstration of Adding Menus Dynamically

 SAMPLE: Code to Demonstrate Superclassing Available

 SAMPLE: MAZE Program from MS Systems Journal Demonstrates DDE

 SAMPLE: Expanding the Size of a Dialog Box

 SAMPLE: Using a Device Driver to Send Binary Data to a Printer

 SAMPLE: Windows Journal Hooks Sample Source Code

 SAMPLE: Using User-Defined Resources in Windows Applications

 SAMPLE: Using Main Window Edit Menu w/ Dialog Box Edit Control

 SAMPLE: Aligning the Logical and Physical Coordinate Systems

 SAMPLE: Multiple Application Instance Data in a DLL

 SAMPLE: Code to Access New .EXE File Headers

 SAMPLE: Creating a User-Defined Control

 SAMPLE: Sharing Global Memory Between Applications

 SAMPLE: Creating the Default Border Around a Push Button

 SAMPLE: QuickSort Sample Code for Windows

 SAMPLE: Right Justifying Numbers in a Windows List Box

 SAMPLE: Owner-Draw: Processing WM_DRAWITEM to Draw Controls

 SAMPLE: Owner-Draw: 3-D Push Button Made from Bitmaps with Text

 SAMPLE: Right and Decimal-Alignment in Owner-Draw Controls

 SAMPLE: Placing a Status Bar in an MDI Frame Window

 SAMPLE: Using RegisterWindowMessage for Interapp Communication

 SAMPLE: MENUITEMTEMPLATE Structure Is Documented Incorrectly

 SAMPLE: Controlling the Horizontal Scroll Bar on a List Box

 SAMPLE: Demo of a Keyboard Hook Function Keyboard Filter

 SAMPLE: Drawing a Custom Border Around a Control Window

 SAMPLE: MUSCROLL Custom Control Code in Software Library

 SAMPLE: Generic Custom Control Sample Code in Software Library

 SAMPLE: Controlling the Horizontal Scroll Bar on a List Box

 SAMPLE: System Bitmaps Available Through LoadBitmap() Data

 SAMPLE: Developing a Spreadsheet Application for Windows

 SAMPLE: Sample Code Using a Dialog Box as the Main Window

 SAMPLE: DLL Installs an ISR That Can Signal an Application

 SAMPLE: Sample Code Uses PatBlt to Drag a Frame Rectangle

 SAMPLE: Windows Code to Parse MS-DOS Environment Variables

 SAMPLE: Code Stores Resources in a Dynamic-Link Library

 SAMPLE: Using IsDialogMessage to Simulate a Dialog Box

 SAMPLE: Printing Text Reports

 SAMPLE: Simulating Drag-and-Drop Interface for Custom Control

 SAMPLE: WinQuickSort(), qsort() Replacement for Windows

 SAMPLE: Code to Provide Time and Date Information

 SAMPLE: Code to Extract an Icon from a Windows .EXE File

 SAMPLE: Owner-Draw Menu Item Width Includes a Check Mark Width

 SAMPLE: Writing Volume Labels to Floppy and Hard Disks

 SAMPLE: Minimal MDI Application Source in Software Library

 SAMPLE: BACKGRND Demonstrates Background Processing

 SAMPLE: Data Input Verification for Edit Controls

 SAMPLE: Alternate MDI Tiling Scheme Code Sample Available

 SAMPLE: Appending Menu Items to Other Applications

 SAMPLE: TOOLHELP.DLL Functionality Demonstration

 SAMPLE: DDE Sample Code in Software Library

 SAMPLE: Dynamically Changing Icons in a Modal Dialog Box

 SAMPLE: Implementing Sizable Form Fields in Windows

 SAMPLE: Palette Animation in Windows

 SAMPLE: Using the Palette Under Windows

 SAMPLE: Code to Demonstrate a Button Bar

 SAMPLE: Changing the Parent of a Child Window Using SetParent

 SAMPLE: Changing the Default Background Color of an MDI Client

 SAMPLE: Code Sample Manages Printing Reports in Applications

 SAMPLE: Scrolling Dialog Box Sample Code in Software Library

 SAMPLE: DLLFLOAT Converts Floating-Point Numbers to Strings

 SAMPLE: Mapping Modes Code Example

 SAMPLE: Creating Accelerator Tables Dynamically

 SAMPLE: Using DrawPenData() or RedisplayPenData() to Display Ink

 SAMPLE: High-Resolution Timing Services

 SAMPLE: ENTER & TAB Keys in Dialog Box Multiline Edit Control

 SAMPLE: Creating a Custom Raster Font

 SAMPLE: Demonstration of WH_CALLWNDPROC & WH_GETMESSAGE Hooks

 SAMPLE: Code Replaces sscanf in DLLs for Windows

 SAMPLE: Writing a Windows Application Using MASM 6.0

 SAMPLE: Changing Color Bitmaps to Monochrome

 SAMPLE: Raising Text Size Limit for Edit Controls

 Sample Source Code Demonstrates Playing Metafiles

 SAMPLE: Modal Dialog Child of Modeless Dialog Box Sample Code

 Sample Help File Demonstrates Win 3.1 Help Macros

 SAMPLE: DDEML with Metafiles

 SAMPLE: Code Demonstrates Using Dialog Box Templates

 SAMPLE: Code Demonstrates an Application Sign-On Screen

 SAMPLE: Code Demonstrates Using TrackPopupMenu

 SAMPLE: Spawn an Application and Wait Sample Code

 SAMPLE: Capturing and Reproducing Ink

 SAMPLE: Changing Size of an Edit Control

 SAMPLE: Preventing Windows from Switching Tasks

 SAMPLE: Switching Between Accelerator Tables in an Application

 SAMPLE: Implementing a Read-Only Edit Control In Windows

 SAMPLE: Code Demonstrating Background Processing in Windows

 SAMPLE: Code Demonstrates SystemParametersInfo()

 SAMPLE: DeviceCapabilities Function Sample Code

 SAMPLE: Code Demonstrates Windows 3.1 WH_MOUSE Hook

 SAMPLE: Code Demonstrates Using a WH_KEYBOARD Hook

 SAMPLE: Code Demonstrates Multiple Instance DLL

 SAMPLE: Code Extracts and Displays Application Resources

 SAMPLE: Common Dialogs and Printing Functions Sample Code

 SAMPLE: DIBs and Their Uses

 SAMPLE: Multiline Edit Control Overwrite Mode Sample Code

 SAMPLE: Sample Code Demonstrates an Owner-Draw Combo Box

 SAMPLE: Code Implements a "Tool Box" Window

 SAMPLE: Using mciSendCommand() to Control CD-ROM Drive

 SAMPLE: Controlling the CD Using mciSendCommand()

 SAMPLE: Detecting Multimedia Extensions and Drivers

 SAMPLE: Controlling a Videodisc Player

 SAMPLE: Program Demonstrates Edit Control Validation

 Sample Application Demonstrates Using DDEML

 SAMPLE: Code Demonstrates Creating Dialog Box in DLL

 SAMPLE: TrueType Functions and Structures

 SAMPLE: Code Displays 256-Color DIB on Standard VGA

 SAMPLE: Navigating a Windows Help File Topic Hierarchy

 SAMPLE: Reading and Converting Between the Three GDI Resources

 SAMPLE: Code Uses Keyboard Hook to Access Help

 SAMPLE: Save and Restore Window Size, Position, Sample Code

 SAMPLE: Unlocking Large-Model Extra Data Segments

 SAMPLE: Code Demonstrates Flashing an Edit Control

 Sample Code Demonstrates Using Private Dialog-Box Class

 SAMPLE: Windows 3.1 Window Styles

 SAMPLE: Executing Excel Functions with Return Values Using DDE

 SAMPLE: Creating a Shortcut-Key Edit Control

 SAMPLE: Adding and Removing Caption of a Window

 SAMPLE: Code Demonstrates How to Add Menus to a Dialog Box

 SAMPLE: Undesirable Interactions Between Dialog Box Types

 SAMPLE: TERMWAIT Spawns Task and Waits for its Termination

 SAMPLE: DLLSKEL Demonstrates DLL and Calling Application

 SAMPLE: Code Simulates Changing List Box Style

 SAMPLE: Code Demonstrates Superclassing MDI Client Window

 SAMPLE: Code Demonstrates Changing Dialog Box Size

 SAMPLE: Code Demonstrates Keeping an Icon Fixed in Place

 SAMPLE: Read-Only Edit Control Compatible with Windows 3.0

 SAMPLE: Code Demonstrates Window Status Bar

 SAMPLE: Application Dynamically Links to a DLL Using a Class

 SAMPLE: Application Shows Microsoft Foundation Classes

 SAMPLE: Code Modifies the Font Common Dialog Box

 SAMPLE: Application Splits a Window into Two Panes

 SAMPLE: Using the LZFILE Functions

 SAMPLE: Using the Dynamic Data Exchange Management Library

 SAMPLE: Creating a Glossary Button in Windows Help

 SAMPLE: Passing Ink Between Hedit Controls

 SAMPLE: Annotating a Text File with Ink

 SAMPLE: DYNBEDIT Changes From Edit to Bedit Control @ Run Time

 SAMPLE: Handling Callbacks with C++ Member Functions

 SAMPLE: Demonstration of Using _fmalloc

 SAMPLE: VERSTAMP Accesses the File Version Information Resouce

 SAMPLE: Using Microsoft C Compiler Options with Windows

 SAMPLE: Windows Application Produces Stack Trace

 SAMPLE: Corrections to the Windows 3.1 SDK Sample FONTEST

 SAMPLE: Maintaining a Hidden Application

 SAMPLE: DDEML Samples Using Microsoft Foundation Classes

 SAMPLE: Infinite Loop When Moving Through Dialog Box Control

 SAMPLE: Code Implementing a Child Window with Menus

 SAMPLE: Bitmap Manipulation Techniques

 SAMPLE: Copying a File

 SAMPLE: DLL Which is Callable from Microsoft Setup Script

 SAMPLE: Windows Application to Unload DLLs from Memory

 SAMPLE: Windows Code Module to Delete Files

 SAMPLE: DRAGBMP Demonstrates Dragging Bitmaps on the Screen

 SAMPLE: FADE Demonstrates Fading Bitmaps w/ Pallette Animation

 SAMPLE: GDIWATCH Uses Tool Helper Library to Walk Heap

 SAMPLE: RLEAPP Demonstrates Animations Using DIB RLE Format

 SAMPLE: WINCAP Captures Screens Using DIB API

 SAMPLE: MAKEAPP Demonstrates Using WINDOWS.H STRICT Option

 SAMPLE: MFCDIB Demonstrates Defining a DIB with MFC

 SAMPLE: SHOWGRP Demonstrates Reading Group Files

 SAMPLE: WINQUERY Demonstrated SQL Server Queries

 SAMPLE: XTENSION Demonstrates a File Manager Extension DLL

 SAMPLE: BADAPP Intentionally Forces a GP-Fault or Hang

 SAMPLE: FAULT Demonstrates Exception and Fault Trapping

 SAMPLE: ISHANDLE Demonstrates Validating Handles

 SAMPLE: MULTAPP is a Multi-Instance DLL with Separate Data

 SAMPLE: MIDIKEYB Demonstrates the midiKeyB Control

 SAMPLE: ZYZGAUGE Demonstrates a Progress Bar

 SAMPLE: GRID Demonstrates Circle Gestures and Much More

 SAMPLE: HOTSPOTS Recognizes Hotspots Associated with Gestures

 SAMPLE: SUBCLASS Subclasses an Edit Control Using MFC

 SAMPLE: PRESSURE Demonstrates Capturing Pressure Information

 SAMPLE: RCDUMP Displays the RCRESULT Structure

 SAMPLE: HEALTH is a Visual Basic Pen Healthcare Application

 SAMPLE: INSURE2 Visual Basic Pen Insurance Application

 SAMPLE: LOANAPP Sample Pen Loan Application

 SAMPLE: RECEIPT Order Application for Pen Windows

 SAMPLE: SALEANAL Forcast Tracking Application for Pen Windows

 SAMPLE: Floating-Point Samples for Windows

 SAMPLE: TOOLBAR Demonstrates Creating a Toolbar

 SAMPLE: Launching One Application for Windows from Another

 SAMPLE: FAULTS.RTF - Technical Article

 SAMPLE: GetGlyphOutline() Function Demonstration

 SAMPLE: MINMAX Demonstrates the WM_GETMINMAXINFO Message

 SAMPLE: Palette Utilization Demonstration

 SAMPLE: Window Hierarchy and Styles

 SAMPLE: TRANSBLT Demonstrates Bitmaps with Transparency

 SAMPLE: A Virtual List Box Implementation

 SAMPLE: Hierarchical List in Owner-Draw List Box

 SAMPLE: FONTUTIL.RTF - Technical Article

 SAMPLE: Implementing Owner-Draw Combo Boxes

 SAMPLE: Measuring System Timings by Using Printer Port

 SAMPLE: DDEEXEC Demonstrates DDE Execute Strings

 SAMPLE: DDESERV Demonstrates a Basic DDE Server

 SAMPLE: Global Heap Functions

 SAMPLE: PATPOLY Demos Polygon Filled with Dithered Color

 SAMPLE: Annotating and Printing Text and Ink Together

 SAMPLE: Advanced ALC_ Sample and ShowKeyboard() Sample

 SAMPLE: VIEW Demonstrates Drawing Ink at a Slower Rate

 SAMPLE: Simple Training Techniques for a Recognizer

 SAMPLE: Customizing the MDI Window Menu

 SAMPLE: Shell DDE Using DDEML

 SAMPLE: Changing Background and Text Color of Message Box

 SAMPLE: Connect Net Drive--a File Manager Extension

 SAMPLE: Accelerators for File Manager Extensions

 SAMPLE: lstrcmpi, Accented Chars, and Sort Order in Windows

 SAMPLE: Port Trapping in Windows 3.0/3.1

 SAMPLE: Reading the Boot Sector of a Drive

 SAMPLE: Mini Title Bars for Windows

 SAMPLE: Desiging DLLs for Multiple Client Applications

 SAMPLE: Printing in Visual Basic and C

 SAMPLE: Updating the Screen Without Flicker

 SAMPLE: Animation in Windows

 SAMPLE: Synchronizing Applications with CD Audio

 SAMPLE: Testing to See if a Drive is a CD-ROM

 SAMPLE: Trapping System RIPs and Other Notification Messages

 SAMPLE: Processing Nonclient Messages with Msg Blaster Control

 SAMPLE: Mixed-Language Application (VB, COBOL, SQL)

 SAMPLE: Visual Basic Using Windows DLLs

 SAMPLE: DDE Communication Over a Network

 SAMPLE: DDE Client Over a Network

 SAMPLE: Moving an Item in a List Box Using Drag and Drop

 SAMPLE: Retrieving Status of Text Box Using Windows Messages

 SAMPLE: BitBlt and StretchBlt Animation

 SAMPLE: GDI Region, Clipping, and Bitmap Functions

 SAMPLE: File Input and Output in Visual Basic

 SAMPLE: Using DDE to Create Program Manager Groups and Items

 SAMPLE: Demonstrates BitBlts to Shuffle Around the Screen

 SAMPLE: Code Demonstrates Dynamic Child Dialog Boxes

 SAMPLE: Rebooting an MSSetup Script on User Request

 SAMPLE: Subclassing VBX Controls with MFC 2.0

 SAMPLE: INIHEADR Sample Reads Section Headers from .INI Files

 SAMPLE: Sample Demonstrates Read-Only Pop-Up Window w/ Shadow

 SAMPLE: SpawnAndWait DLL Provides Synchronous Spawn Function

 SAMPLE: Dialing a Modem in Windows 3.1

 SAMPLE: Paging Down in an Owner-Draw Variable List Box

 SAMPLE: Using ExtDeviceMode() to Modify Printer Settings

 SAMPLE: Implementing a List Box Full of Dialog Boxes

 SAMPLE: WFW Named Pipe Client

 SAMPLE: Plotting TrueType Characters

 SAMPLE: Troubleshooting Guide for the 16-bit Setup Toolkit

 SAMPLE: Open Multiple AVIs, Use of MCI_PUT Command

 SAMPLE: SPINDIB Demonstrates 90-degree DIB Rotation

 SAMPLE: Using MCI Commands in Visual Basic

 SAMPLE: Direct-to-Disk Recorder with ACM

 SAMPLE: Multimedia Registration Kit revision 3.0

 SAMPLE: SNDPLAY Sample Plays a Sound File

 SAMPLE: MIDIIO Sample Demonstrates MIDI Input and Output

 SAMPLE: MIDISX.EXE Demos MIDI System Exclusive Communication

 SAMPLE: Reading and Writing Aldus Placeable Metafiles


Definition of a Region

Article ID: Q10212

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The term "region" is used throughout the Windows documentation; however,

the term is not defined. This article explains regions, how they are used,

and how a region is defined or specified.

MORE INFORMATION

================

Unlike most graphics packages that can manipulate only simple geometric

structures (usually rectilinear), The Windows graphics device interface

(GDI) has the unique ability to gather an arbitrary set of spatially

coherent points into a structure called a region, and perform complex yet

rapid manipulations and calculations on such structures. This feature not

only makes standard programs simpler and faster, it also allows operations

to be performed that would otherwise be nearly impossible (for example, it

is fundamental to the implementation of the Windows user interface).

Although most GDI function parameters are given in logical units and then

are converted to device units, region function parameters are given in

device units.

A region is defined by defining lines, shapes (such as rectangles and

ellipses), or other regions. The outline of a region should be one or

more closed loops. A region can be concave or convex, can consist of

one area or many disjoint areas, and can have "holes" in the middle.

Many calculations can be performed on regions. For example, given any

two regions, GDI can find their union, intersection, difference, and

exclusive. There is a set of graphic operations on regions to draw

them on the screen.

When a region is selected into a device context (DC), a new clipping

area is created. Any graphics sent to that DC will be clipped to the

region created. Regions are defined using CreateRectRgn(),

CreateEllipticRgn(), and CreatePolygonRgn().

Additional reference words: 3.00 3.10

KBCategory: kbprg kbref kbdocerr

KBSubcategory: GdiDrw


GDI Simulation Routines and Device Drivers for Windows

Article ID: Q10834

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

The following information concerns GDI's simulation routines for

device drivers:

GDI discards its simulation routines when more intelligent drivers

provide the required information. GDI is demand-loadable and

discardable. When a smart driver registers its capabilities with GDI,

GDI dumps the simulation routines that it uses for less intelligent

display drivers. For example, when writing a driver that can handle

all the OUTPUT functions, GDI will avoid loading all the simulation

routines.

In addition, GDI's simulation routines are optimized. However, it is

usually the case that device drivers can complete output functions a

lot faster because no GDI object or memory must be allocated during

the operations, and device drivers can deal directly with the hardware

device.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDisplay


A Discussion of Windows Fonts

Article ID: Q10837

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following discussion on Windows fonts describes how they are

defined and why they are necessary.

MORE INFORMATION

================

How Default Fonts Are Assigned

------------------------------

At the API level, Windows version 3.0 defines six stock fonts. Each of

these fonts has a logical description. At Windows 3.0 boot time, GDI

constructs the logical description of these fonts in the following

manner:

1. During its initialization, GDI calls an internal function,

   InitFonts(), which is responsible for physically loading three

   basic fonts. Under a typical Windows 3.0 installation, the names of

   the font files for these fonts are listed in the [boot] section of

   the SYSTEM.INI file. For example, this section (in part) resembles

   the following:

      fixedfon.fon=vgafix.fon

      oemfonts.fon=vgaoem.fon

      fonts.fon=vgasys.fon

   The system font is loaded first. GDI first checks the WIN.INI file

   in the [windows] section for the key name SystemFont=<file>, where

   <file> is a name of a bitmap font (such as HELV.FON). If GDI finds

   this keyname, it will attempt to load the specified file as the

   system font. Changing this value is one method the user can use to

   customize the system font.

   NOTE: If you change SystemFont=<font> you *must* also have the line

   fonts.fon=<font> in the [windows] section of the SYSTEM.INI file.

   Otherwise, Windows will not load properly.

   If GDI does not find this key name, it attempts to load the system

   font from a file called FONTS.FON using the GDI function

   AddFontResource. Notice that on typical installations of Windows

   3.0, there is no file called FONTS.FON. AddFontResource calls

   LoadLibrary to load the specified file. If the file is not found,

   LoadLibrary will search the SYSTEM.INI file (in the [boot] section)

   for a redirection of the file. As shown above, the [boot] section

   of SYSTEM.INI for a VGA system contains the following:

      fonts.fon=vgasys.fon

   This line indicates that the system font should be loaded from the

   file VGASYS.FON, which resides in the system directory.

2. Once the system font is physically loaded, GDI attempts to load a

   fixed-pitch font. GDI examines the [boot] section of the SYSTEM.INI

   file and extracts the filename from the fixedfon.fon= field. If no

   file is specified, the system font (loaded in step 1) is

   substituted for the system fixed-pitch font.

3. Next, the terminal font is loaded. GDI attempts to load the file

   OEMFONTS.FON (via AddFontResource). This file may be redirected in

   the same manner as the system font in step 1.

4. Later during its initialization, GDI gets the module handle of

   DISPLAY. Using the module handle, it does a FindResource() on the

   resource string "fonts", which is an array of three LOGFONT

   structures that have been defined by the display driver

   manufacturer. This is the resource that is included in the display

   driver's .RC file with the line:

      fonts   oembin  PRELOAD         fonts.bin

   Once this resource is found, GDI steps through the array of

   LOGFONTS and calls CreateFontIndirect to create the stock font

   objects:

      OEM_FIXED_FONT

      ANSI_FIXED_FONT

      ANSI_VAR_FONT

   These logical font definitions can be thought of as recommendations

   for a particular display by the display driver.

   In general, these logical font descriptions will map to one of the

   physical fonts loaded initially by GDI.

   However, when an application selects one of these stock fonts, the

   font mapper selects the closest matching font from a list of

   available physical fonts in the system. This list contains the

   initial system fonts that were loaded by GDI, in addition to other

   fonts that may have been loaded at a later time. Therefore, there

   is no guarantee that a given stock font will necessarily map to one

   of the three initial fonts loaded by GDI.

5. Once these three stock fonts have been defined, GDI defines the

   stock font SYSTEM_FONT. GDI does this by opening the system font

   file loaded in step 1 and builds a logical font structure that

   exactly matches the physical characteristics of the physical font.

   This is to ensure that the font mapper will select this physical

   font when the SYSTEM_FONT stock font is requested.

6. Finally, the logical description of the device default font

   (DEVICE_DEFAULT_FONT) is defined. This font is defined to be the

   same as the SYSTEM_FONT.

Why These Fonts Are Necessary

-----------------------------

There are two reasons for having these six stock fonts. One reason is

to provide an OEM font that displays well at 10 pitch on the machine.

This font is also used to determine the height of dialog boxes. The

second reason is to provide ANSI fonts that are based on proposed

standards (device-independent) and match Microsoft's virtual-key

definitions.

Please note that all of these fonts are required. The display driver

must include the three logical fonts (described above) or GDI will not

initialize properly.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiFnt


CreatePen() and CreatePenIndirect() Use Predefined Styles

Article ID: Q11270

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

In Windows, the CreatePen() and CreatePenIndirect() calls only allow the

creation of a pen with predefined styles (for example, solid, dash, and

dot). It is not possible to create a pen with a unique style. The only

styles available are the stock pens and styles provided with Windows.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPnbr


Printer Page Area in Windows

Article ID: Q11863

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article describes how to determine the printable area for a printer in

Windows.

MORE INFORMATION

================

Escape(GETPHYSPAGESIZE) specifies the size of the physical sheet of the

currently selected paper size; for example, 8 1/2 by 11 for letter-sized

paper on the Epson FX-80.

Escape(GETPRINTINGOFFSET) specifies how far in and how far down the

printable area starts on the sheet of paper; for example, 1/4 inch in and

1/8 inch down for the Epson.

GetDeviceCaps(HORZSIZE) specifies the width of the printable area on the

page, in millimeters (8 inches for the Epson).

GetDeviceCaps(VERTSIZE) specifies the length of the printable area on the

page, in millimeters (10 inches for the Epson).

GetDeviceCaps(HORZRES) specifies the width of the printable area on the

page, in pixels. Note that this value will depend on the currently selected

graphics resolution (960 for the Epson at 120 x 72 DPI or 120 x 144 DPI,

1920 for the Epson at 240 x 144 DPI).

GetDeviceCaps(VERTRES) specifies the length of the printable area on the

page, in pixels. Note that this value will depend upon the currently

selected graphics resolution (720 for the Epson at 120 x 72 DPI, 1440 for

the Epson at 120 x 144 DPI or 240 x 144 DPI).

If pixels per inch are desired, GetDeviceCaps(LOGPIXELSX and LOGPIXELSY)

gives the number of pixels per inch in each direction (120 per inch

horizontal, 72 per inch vertical for Epson). Please note that these

arguments were not documented prior to Windows version 3.0.

Device coordinates are returned; therefore, conversion to logical

coordinates is necessary before drawing with GDI.

The origin of the printable area is 0,0. The rectangle that defines the

printable area is as follows:

   left = 0

   top  = 0

   right = GetDeviceCaps (HORZSIZE)

   bottom = GetDeviceCaps (VERTSIZE)

Using the above example for the Epson, the paper is 8 1/2 by 11 inches.

Horizontally, the printable area goes from 1/4 inch to 8 1/4 inches;

vertically, the printable area goes from 1/8 inch from the top to 10 1/8

inches.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Restoring Objects in a Metafile DC

Article ID: Q19899

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

A display context for a metafile does not have any default objects

when it is created. When SelectObject() is passed the hDC of a

metafile, SelectObject() will return 1 if the operation is successful

and NULL if the operation fails.

Objects that have been selected into a metafile display context should be

deleted directly by calling DeleteObject(hObject) after you have selected

the object out of the DC. DeleteObject() is supported for Windows version

3.x metafiles only. Objects selected into other display contexts should be

deleted by calling DeleteObject (SelectObject (hDC, hOldObject)).

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDc


Using a Different Hardware Font Instead of the Default

Article ID: Q22131

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following information describes how to inform Windows that a

specific hardware font in a display device driver should be used

instead of the default system font.

In general, an OEM provides an .FON file that contains bitmaps and

metric information that is appropriate for the display board. This

font file is listed in the SYSTEM.INI file in the [boot] section as

follows:

   fonts.fon=<OEM's .FON file>

At startup, GDI creates the SYSTEM_FONT stock font from this file.

If the display board has a hardware font available, it is possible to

force GDI to use this font as the SYSTEM_FONT font by creating an .FON

file that contains no bitmap information and has the third bit (04h)

set in the dfType field and the absolute address of the hardware font

in the dfBitsOffset field in the FONTINFO structure contained in the

.FON file.

NOTE: It must be possible to draw that same font (or any other

hardware fonts that are provided within the display device driver)

onto main-memory bitmaps. GDI has no notion of some fonts being used

on the (dedicated) frame buffer and other fonts being used on

host-memory bitmaps. Often, this requires that the hardware font be

read off of the board and into host memory where the display device

driver can move the bitmaps onto compatible bitmaps allocated by GDI.

Within these guidelines, and with that provision in mind, the

programmer can feel free to provide the system, OEM, and so on, with

as many additional fonts as are desired (say, from Bitstream, Xiphias,

or Conographics).

For additional information on how Windows creates stock fonts, please see

the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q10837

   TITLE     : A Discussion of Windows Fonts

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiFnt


Windows DEVICEDATA Escape Usage

Article ID: Q22135

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following provides information about the usage of the DEVICEDATA

escape.

MORE INFORMATION

================

The term "#define DEVICEDATA 19" was previously called PASSTHROUGH;

however, it was later renamed. Using the DEVICEDATA escape, which is

essentially a "pass-through" to the device, will make an application

absolutely device dependent.

The primary use of the DEVICEDATA escape is to download information

that needs to be in the printer (that is, information that should be

there, however, the programmer knows is not there) or to set the

printer state. The DEVICEDATA escape will not interact with the GDI in

a reasonable way; however, it allows device-driver writers to provide

escapes directly into a printer for functions supported there. In

particular, if the state in a printer is set to something other than

what GDI thinks it to be, the results could be unpredictable. For

example, a simple dump of text strings could be sent to a device.

However, the programmer must be sure that the printer is in text mode

(that is, not in graphics mode) before the programmer attempts this

procedure.

A better way to perform a "quick and dirty" print is to set the

requested print quality to Draft. Time-conscious drivers would

probably use intrinsic fonts for draft-quality printing (no assertion

has been made that there are any drivers out there that actually do

this; it is part of the semantics of draft-quality printing).

To summarize this information, the DEVICEDATA escape provides a simple

way to send a string of bytes to a device; however, it does not

provide a simple way to print to the device. It is device-dependent as

to whether those bytes get printed, are interpreted as a downloaded

font, reset printer characteristics, and so on. The DEVICEDATA escape

should not be considered a substitute for using the GDI interface. For

these reasons, Microsoft recommends that this escape never be used by

well-behaved applications.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Information About Clipping, GetDeviceCaps() and GDI

Article ID: Q22538

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When the GetDeviceCaps(hDC,CLIPCAPS) function is used on an Epson

FX-80 printer, it returns zero (0), which means that the printer does

not support clipping. The explanation below describes how the

GetDeviceCaps() function, the Windows Graphics Device Interface (GDI),

and clipping interact with each other.

The GetDeviceCaps() function reports what subset of the GDI services

the device directly supports. The complete list of GDI services is

available in the documentation. The GDI will simulate functions that

the device does not directly support using those functions that are

available on the device.

The Epson FX-80 printer does not support clipping to any particular

portion of the page, even in graphics mode, which is precisely what

the GetDeviceCaps() function indicates.

GDI provides at least a minimum level of services for all devices. In

particular, if a clipshape is set while a document is being printed,

the programmer can be assured that GDI will honor that clipshape. GDI

works with the information returned in the GetDeviceCaps() function to

determine what services GDI must provide on behalf of the device. In

this case, the printer does not perform clipping; clipping is provided

by GDI. The GetDeviceCaps() function can indicate how much additional

work GDI must perform to accomplish a particular function. The

programmer may want to modify a request to speed processing.

Also note that DC stands for device context. The most interesting DC

is for the display [and, in fact, it is the device context for the

display that is returned by GetDC(), and in the PAINTSTRUCT structure

returned by BeginPaint()]. Printer DCs are NEVER contexts for the

display; they are device contexts.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDc


Print Manager Print Job File Limit and WM_SPOOLERSTATUS

Article ID: Q26000

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows versions 3.0 and earlier Print Manager, the print

queue is limited to a total of 20 jobs. After 20 files have been sent to

the queue, another file cannot be printed from an application until one of

the spooled files has finished being sent to the printer.

The print queue limit for Print Manager under the Windows Operating System

version 3.1 is 100 print jobs.

An application can process the WM_SPOOLERSTATUS message to determine when a

job is added to or removed from the Print Manager queue. This message also

provides the number of jobs remaining in the queue. Please see the

documentation for WM_SPOOLERSTATUS for more information.

The following code fragment demonstrates use of the WM_SPOOLERSTATUS

message:

   case WM_SPOOLERSTATUS:

      if (wParam == SP_JOBSTATUS)

         {

         itoa ( LOWORD(lParam), buff, 5);

         MessageBox( hWnd, (LPSTR)buff,

             (LPSTR)"Number of Jobs Remaining", MB_OK);

         }

      else

         {

         itoa ( wParam, buff, 5);

         MessageBox( hWnd, (LPSTR)buff,

             (LPSTR)"Unknown Spooler Message", MB_OK);

         }

      break;

Additional reference words: 3.00 3.10 spooler

KBCategory: kbprg

KBSubcategory: GdiPrn


PRB: PlayMetaFile() Not as Fast as More Complex Technique

Article ID: Q28344

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The PlayMetaFile() function is slower than using a loop that contains

the EnumMetaFile() and PlayMetaFileRecord() commands.

CAUSE

=====

PlayMetaFile() takes longer because it plays the metafile records, and it

also performs several additional steps:

1. Verifies that its handle parameter points to a valid metafile.

2. Locks the metafile.

3. Saves all objects in the device context (pens, brushes, regions,

   etc.).

4. Plays the metafile records.

5. Restores all objects in the display context. PlayMetaFile() will

   restore default objects if other restoration fails.

6. Unlocks the metafiles.

7. Deletes all objects created while playing the metafile.

To achieve this speed advantage, the callback function specified in

EnumMetaFile() would call only PlayMetaFileRecord(). The actual speed

of execution is determined by the amount of processing done in the

EnumMetaFile() callback function.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiMeta


Drawing a Different Icon for Each Application Instance

Article ID: Q29733

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

An application can use the DrawIcon function in its paint procedure to

display a different icon for each application instance. The method

(outlined below) has five steps.

MORE INFORMATION

================

1. In the WNDCLASS data structure used to register the application's

   main window class, set the hIcon field to NULL. This prevents

   Windows from drawing an icon when the application is minimized. The

   following code demonstrates this step:

   int index;  // global variable to count application instances

   // This function initializes the first application instance

   void InitFirst(HANDLE hInstance)

   {

      WNDCLASS rClass;            // window class structure

      rClass.lpszClassName = "HELLO";

      rClass.hInstance     = hInstance;

      rClass.lpfnWndProc   = WindowProc;

      rClass.hCursor       = LoadCursor(NULL, IDC_ARROW);

      // If hIcon is NULL, Windows will not draw icon. Application

      // paints its own icon as appropriate.

      rClass.hIcon         = NULL;

      rClass.lpszMenuName  = NULL;

      rClass.hbrBackground = COLOR_WINDOW + 1;

      rClass.style         = CS_HREDRAW | CS_VREDRAW;

      rClass.cbClsExtra    = 0;

      rClass.cbWndExtra    = 0;

      RegisterClass(&rClass);     //  register the class

      index = 1;  // set counter to indicate first instance

   }

2. The GetInstanceData function provides the value of the instance

   counter from the previous instance. Adding one to this value

   provides the value for the current instance, as follows:

   void InitNext(HANDLE hInstance, HANDLE hPrevInstance)

   {

      GetInstanceData(hPrevInstance, (PSTR)&index, sizeof(int));

      index++;

   }

3. During the instance initialization function, load the icon for the

   current instance from the application's resources. In this case,

   Icon1, Icon2, Icon3, and Icon4 are individual icons declared in the

   application's resources. The following code demonstrates this

   procedure:

   HICON hIcon; // icon handle for this instance

   void InitEvery(HANDLE hInstance, int cmdShow)

   {

      HWND  hWnd;

      hInst = hInstance; // store instance in global variable for

                         // window procedures to use

      switch (index)

         {

      case 1: hIcon = LoadIcon(hInstance, "Icon1");

              break;

      case 2: hIcon = LoadIcon(hInstance, "Icon2");

              break;

      case 3: hIcon = LoadIcon(hInstance, "Icon3");

              break;

      default:

              hIcon = LoadIcon(hInstance, "Icon4");

         }

      CreateWindow( ... ); // and so forth

   }

4. When an application receives a WM_PAINT message while the window

   is minimized, draw the icon in the application's client area. The

   IsIconic function returns TRUE if the application is minimized.

   The following code demonstrates this step:

   // In the switch(message) statement of the main window procedure

   case WM_PAINT:

      {

      PAINTSTRUCT ps;

      if (IsIconic(hWnd))

         {

         BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);

         // Paint the desktop window background.

         DefWindowProc(hWnd, WM_ICONERASEBKGND, (WORD)ps.hdc, 0L);

         // Draw the icon in the cleared area

         DrawIcon(ps.hdc, 0, 0, hIcon);

         EndPaint(hWnd, (LPPAINTSTRUCT)&ps);

         }

      else

         // Paint the window as usual

      }

5. When the user drags an application's icon with the mouse and the

   application processes the WM_QUERYDRAGICON message as follows,

   Windows changes the mouse cursor to a black-and-white

   representation of the application's icon.

   // In the switch(message) statement of the main window procedure

   case WM_QUERYDRAGICON:

      return (LONG)(WORD)hIcon;

      break;

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiCurico


Font Metrics and the Use of Negative lfHeight

Article ID: Q32667

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following illustrations show the most commonly used font metrics,

including Character Height, which is selected with negative values of

lfHeight.

Each illustration is followed by notes describing the metrics.

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

                     O    O

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

                       /\

                      /  \

                     /    \

 _ _ _ _ _ _ _ _ _  /______\ _ _ _ ___   _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

                   /        \     /   \|

                  /          \   |     |

 _ _ _ _ _ _ _ _ /_ _ _ _ _ _ \ _ \___/| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

                                       |

                                       |

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\___/_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

                                                      |

                                                      |- External Leading

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _

                                                      |

                     O    O                           |- Internal Leading

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _

              |        /\

              |       /  \

              |      /    \

              |     /______\ _ _ _ ___   _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

 Char Height -|    /        \     /   \|

              |   /          \   |     |

              |  /_ _ _ _ _ _ \ _ \___/| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

              |                        |

              |                        |

 _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _\___/_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

              |                                           |

              |      O    O                               |

              |                                           |

              |        /\                                 |

              |       /  \                                |

              |      /    \                               |- Ascent

 Cell Height -|     /______\       ___                    |

              |    /        \     /   \|                  |

              |   /          \   |     |                  |

              |  /_ _ _ _ _ _ \ _ \___/| _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _

              |                        |                  |

              |                        |                  |- Descent

 _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _\___/_ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _

NOTES

-----

Cell Height

-----------

This is the height selected on positive lfHeight in the LOGFONT. It is

the height of the font bitmap for raster fonts. It is returned as

tmHeight in the TEXTMETRIC structure from GetTextMetrics().

Character Height (Also Known as Em)

-----------------------------------

This is the height selected on negative lfHeight in the LOGFONT. (that

is, the mapper will try to match a font whose character height matches

the absolute value of the requested height). NOTE: By definition, the

Em is equal to Cell Height minus Internal Leading. The Em defines the

point size of a font. In MM_TEXT mapping mode, the Em is related to

the point size as follows:

   Em=dpiY*point_size/72;  // where dpiY is dots per inch in Y direction

The dpiY of a font is equal to tmDigitizedAspectY in TEXTMETRICS.

Internal Leading

----------------

This is returned as tmInternalLeading in the TEXTMETRIC structure from

GetTextMetrics() and often, but not necessarily, describes how much

space has been left inside the font bitmap for diacritical marks

(accents).

External Leading

----------------

This is returned as tmExternalLeading in the TEXTMETRIC structure from

GetTextMetrics() and describes how much extra space the font designer

expects the application to leave between rows of the font. It is not

included in the bitmap and is not modified by TextOut()/ExtTextOut(),

even in OPAQUE mode. When outputting multiple lines of text, the lines

should be separated by (tmHeight + tmExternalLeading).

 Character Width                       Character Width

        |                                     |

 |-------------|                       |-------------|

 |          |                         /          /   |

 |          |                        /          /    |

 |          |                       /          /     |

 |          |                      /          /      |

 |----------|                     /----------/       |

 |          |                    /          /        |

 |          |                   /          /         |

 |          |                  /          /          |

 |          |                 /          /           |

                                            |________|

 |_____________|              |_____________|    |

        |                            |           Overhang

   Character width        Character width

 (including white space)  (including white space)

   Overhang = 0                  Overhang > 0

NOTES

-----

Overhang

--------

tmOverhang specifies the per string extra width that may be added to

some synthesized fonts. When synthesizing some attributes such as bold

or italic, GDI or a device may have to add width to a string on both a

per character and per string basis. For example, GDI synthesizes

embolding by expanding the intercharacter spacing and overstriking

with an offset and italicizes a font by skewing the string.

In either case, there is an overhang past the basic string. For bold

strings, it is the distance by which the overstrike is offset. For

italic strings, it is the amount the top of the font is skewed past

the bottom of the font. tmOverhang allows the application to determine

how much of the character width returned by a GetTextExtent() call on

a single character is the actual character width and how much is the

per string extra width. The actual width is the extent less the

overhang. In other words, tmOverhang is the difference between the

width of a character when it is output singly versus its width when it

is in the interior of a string.

For more information, look up the following topics in the Windows

Software Development Kit reference:

 - CreateFont()    (in Volume 1 of the version 3.0 reference)

 - TEXTMETRIC      (in Volume 2 of the version 3.0 reference)

Or, query on the following word:

   EXTTEXTMETRIC

Additional reference words: fonts metrics lfHeight height TEXTMETRIC

EXTTEXTMETRIC LOGFONT 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiFnt


Expanded BANDINFO Documentation

Article ID: Q33252

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following is an expanded version of the documentation of the

BANDINFO escape in earlier manuals. Refer to the index or table of

contents section to determine where the BANDINFO information is

located in the current versions of the documentation.

   short Escape(hDC, BANDINFO, nCount, lpInData, lpOutData)

MORE INFORMATION

================

Purpose

-------

Provides better communication between a banding driver and the

application.

Parameters

----------

   Parameter     Definition

   ---------     ----------

   hDC           A handle to the printer display context

   nCount        Not used and can be set to NULL

   lpInData      A long pointer to a data structure that has the

                 following structure:

                    typedef struct {

                        BOOL    GraphicsFlag;

                        BOOL    TextFlag;

                        RECT    GraphicsRect;

                        } BANDINFOSTRUCT;

                 This data structure provides the primary

                 communication between the driver and the

                 application as to what (graphics and/or text)

                 is actually on the page. The notes below

                 describe its use.

   lpOutData     A long pointer to a data structure having the same

                 items as lpInData, a BANDINFOSTRUCT

Return Value

------------

   Return Value  Result

   ------------  ------

   nResult       1 if the function is successful

                 0 if the function is not successful or if the escape

                 is not implemented

Notes

-----

This escape is only implemented for devices that use banding to output

to the printer. The escape is called immediately after the NEXTBAND

escape, every time the NEXTBAND escape is called.

The BANDINFO data structure is used to communicate between the driver

and the application as follows:

   Data structure  Used as lpInData            Used as lpOutData

   field           (application communicates   (driver communicates

                   to the driver)              back to the application)

   GraphicsFlag    TRUE if there are graphics  TRUE if the driver is

                   on the page                 expecting graphics in

                                               this band

   TextFlag        TRUE if there is text on    TRUE if the driver is

                   the page                    expecting text in this

                                               band

   GraphicsRect    The bounding rectangle for  No valid return data

                   all graphics on the page

This escape is always executed immediately after a NEXTBAND escape and

is in reference to the band the driver returned to that escape. Listed

below are examples of how the BANDINFO escape can be used to

communicate between driver and application.

1. On the first band, the driver gives the application a full-page

   band and asks for text only (GraphicsFlag == FALSE, TextFlag ==

   TRUE). The application sends only text to the driver.

2. If in the first band the application said it had graphics

   (GraphicsFlag == TRUE), or if the driver encountered any vector

   fonts, the driver will have to band the rest of the page. If

   there are no graphics or vector fonts, the next NEXTBAND escape

   will return an empty rectangle, indicating that the application

   should move on to the next page.

3. If there are graphics and no vector fonts, (that is, the application

   set GraphicsFlag == TRUE), the driver only has to band into the

   rectangle the application passed via NEXTBAND, which bounds all

   graphics on the page. If there are vector fonts, the driver will

   band the entire width and depth of the page with the TextFlag ==

   TRUE.

The driver assumes that an application using BANDINFO will send only

text in the first full-page text band because that is all the driver

asked for. Therefore, if the driver sees a vector font or any graphics

in the band, it assumes they were generated by a text primitive and

sets the TextFlag == TRUE for all of the subsequent graphics bands to

ensure that they can be output as graphics. If the application does

not meet this assumption, the image will still be generated properly;

however, some time will be wasted by sending spurious text primitives

to graphics bands.

Code Outline

------------

The general outline of a routine using BANDINFO to output a page

should be as follows:

   do {

       if (BandingDevice) {

           NEXTBAND

           BANDINFO

           }

       else {

           /* It is not a banding device. */

           /* Set the band to the entire page. */

           BandRect.left   = 0;

           BandRect.top    = 0;

           BandRect.right  = dxPrinter;

           BandRect.bottom = dyPrinter;

           /* Output everything. */

           BandInfoOut.GraphicsFlag = TRUE;

           BandInfoOut.TextFlag     = TRUE;

           }

       if (TextFlag) {

           Do any text.

           }

       if (GraphicsFlag) {

           Do any graphics.

           }

       } while (BandingDevice &&

                more bands to do);

   /* NEWFRAME and NEXTBAND are exclusive; however, at least one must

      be used. Hence we need to do a NEWFRAME if we are not banding. */

   if (!BandingDevice) {

       /* Put out the page. */

       if ((SpoolerError = Escape(hDC, NEWFRAME, 0, 0L, 0L)) <= 0) {

           Result = ConvertSpoolerError(SpoolerError);

           Escape(hDC, ABORTDOC, 0, 0L, 0L);

           goto ErrorExit3;

           }

       }

For more information on full-page banding for text, query on the

following words:

   prod(winsdk) and four and banding and nonraster

For more information on BANDINFO, query on the following words:

   NEXTBAND and NEWFRAME and BANDINFO and banding and printing

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


The Four Classes of Device Banding

Article ID: Q34843

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows environment, banding is a common technique to

divide a page into a number of sections, called bands. When an

application uses banding, it requires less memory to produce a page of

printed output at the potential expense of some additional time. This

article discusses the four types of banding devices that can be used

in the Windows environment: nonbanding devices, simple banding

devices, "Full Page Banding for Text" devices, and BANDINFO devices.

MORE INFORMATION

================

Nonbanding Devices

------------------

These devices do not perform any banding. PostScript printers and

plotters are the most common nonbanding devices. These nonraster

devices accept primitive output directly from Windows without any need

for intermediate rasterization. An application can identify a

nonbanding device by performing the following three steps:

1. Create a device context (DC) for the output device and obtain a

   handle to the device context (hDC).

2. Call the GetDeviceCaps function, specifying the hDC and RASTERCAPS

   for the iCapability parameter.

3. Check the RC_BANDING bit of the GetDeviceCaps function. If the

   RC_BANDING bit of the GetDeviceCaps return value is clear, the

   device does not perform banding.

Simple Banding Devices

----------------------

These devices divide both text and graphics into a series of bands

starting at the top of each page and running to the bottom. Under

versions of Windows earlier than 3.1, these devices may provide a

full-page band when available memory permits, but they usually do not.

Under Windows 3.1, these devices generally provide a full-page band

when memory permits. Dot-matrix printers are the most common simple

banding devices. An application can identify a simple banding device

by performing steps 1 and 2 above. The RC_BANDING bit is set for

simple banding devices.

"Full Page Banding for Text" Devices

------------------------------------

The driver for a page printer (commonly referred to as a laser

printer) typically uses one band covering the full page for text

followed by additional smaller bands for graphics. This technique is

an optimization for a printer that allows text to be placed at any

position on the page but does not have the graphics capabilities of a

PostScript printer. Typically, a driver does not provide any graphics

bands unless it detects a graphics command in its text band. While

this technique allows the driver to optimize printing of pages

containing only text, an application that prints graphics must call a

graphics primitive in the text band to work correctly with this driver

type. Most new page-printer drivers are developed for the fourth

driver category, discussed below.

BANDINFO Devices

----------------

With a BANDINFO device driver, an application can optimize its

printing and eliminate calling graphics primitives in a text band by

requesting graphics bands only when required and identifying which

band is the text band. This BANDINFO escape provides this capability.

An application issues the BANDINFO escape to inform the driver that

the application will print graphics and to determine which bands

contain text and which bands contain graphics.

An application can use the QUERYESCSUPPORT escape to identify a device

that supports the BANDINFO escape. If the driver supports BANDINFO,

the application can determine when to print text or graphics as

appropriate. If the driver does not support the BANDINFO escape, the

application should print text and graphics in each band.

The Hewlett-Packard LaserJet driver is an example of a printer driver

that implements the BANDINFO escape.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


PRB: Some Windows GDI Functions Fail on Banding Printers

Article ID: Q35857

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application prints using the NEWFRAME escape on a banding device

and then tries to use a GDI function that is not supported in metafiles,

the function does not produce any output or produces incorrect output.

CAUSE

=====

Some GDI functions that work on the display fail on banding printers. When

an application prints using the NEWFRAME escape on a banding device, GDI

diverts each page to an intermediate metafile. This metafile is then played

back to each band on the device.

RESOLUTION

==========

The workaround is to use NEXTBAND instead of NEWFRAME on banding devices;

in this case, a metafile will not be used.

Please note that some functions, such as the GetTextMetrics() function and

similar types of functions that do not attempt to produce output, do work

correctly with banding printer drivers because the call is directed to the

printer driver, not the intermediate metafile.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


Windows SDK: Limit of Logical Coordinate System in Windows

Article ID: Q39802

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows version 3.0

----------------------------------------------------------------------

The limits of the logical coordinate system are from -32768 to +32767.

An item can be drawn anywhere within this coordinate system; however,

the window extent cannot be set to greater than 32767. (Although this

might seem to limit the system to the -16384 to 16383 range, this is

not the case.) If the viewport and window are set up properly,

everything will be shown. For example, to set up the whole logical

coordinate system to be shown within the application's area of the

screen, the following code works properly:

/*  Establish viewport to be upper-left quarter of client area */

  GetClientRect(hWnd, (LPRECT) &CRect);

  SetViewportOrg(hDC, 0, 0);

  SetViewportExt(hDC, (CRect.right - CRect.left) / 2, \

                      (CRect.bottom - CRect.top) / 2);

/*  Set Window Origin and Extent such that total logical */

/*     coordinate system will cover entire client area   */

  SetWindowOrg(hDC, -32767, -32767);

  SetWindowExt(hDC, 32767, 32767);

Additional reference words: mapping modes anisotropic isotropic

KBCategory: kbprg

KBSubcategory: GdiDc


EndPage(), NEXTBAND, and NEWFRAME Reset DC Attributes

Article ID: Q40234

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

When the end of a page is reached during printing, the contents of the

device context are reset to the default attributes for the device. This is

true whether you are banding [using Escape(NEXTBAND)] or not [using

Escape(NEWFRAME)].

This information also applies to the EndPage() function, which was

introduced in Windows 3.1.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


GETPHYSPAGESIZE Landscape vs. Portrait Mode

Article ID: Q44094

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The printer driver considers the page to be in Landscape mode when you use

the Escape(..., GETPHYSPAGESIZE, ...) function, if the page width is

greater than the page length.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Changing Printer Parameters from an Application

Article ID: Q51739

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

For an application to use the printer most effectively, sometimes it

is necessary for the user to modify the printer settings. To

accomplish this, an application can activate the settings dialog box

for the printer driver of the currently selected printer.

DEVMODE demonstrates how this may be done. Three steps are required:

1. Load the printer driver.

2. Get the procedure address of the "DEVICEMODE" procedure exported by

   the driver.

3. Call the procedure through the procedure address.

The settings dialog is responsible for obtaining any information from

the user and for saving any changes in the appropriate INI file.

Chapter 17 of the "Microsoft Windows Software Development Kit Guide to

Programming" provides additional information on this procedure.

Download DEVMODE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DEVMODE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DEVMODE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DEVMODE.EXE

Additional reference words: 3.10 3.00 softlib

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


Changing the Palette of Colors on a Nonpalette Device

Article ID: Q62740

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The text below discusses methods by which an application for the

Microsoft Windows graphical environment can change the colors

displayed on a display device that does not support a color palette (a

nonpalette device). Specifically, this article discusses selecting 16

nondefault colors for a VGA 16-color driver.

MORE INFORMATION

================

Windows version 3.0 introduces a set of palette mapping functions that

allow an application to choose what colors are available in the

hardware palette when the application is active. However, these

functions work only with devices that support 256 or more colors, and

have drivers designed for palette support.

There are some devices that can show a limited number of colors at one

time, but choose those colors from a much larger set of available

colors. For example, the standard VGA screen can display 16 colors at

a time, but can choose those 16 colors from a palette of approximately

256,000 colors. Because it can display only 16 colors at once, the VGA

driver shipped with Windows does not implement the palette functions.

When an output device has a programmable color palette, its device

driver can implement the SETCOLORTABLE escape through which an

application can specify its desired colors. Note, however, that the

display drivers (EGA, VGA, and so on), which Microsoft ships with

Windows versions 3.0 and 3.1, do not support this escape. A custom

device driver is required to provide this functionality. The

application should send the QUERYESCSUPPORT escape to the driver to

determine whether the escape is supported.

NOTE: The implementation and use of the SETCOLORTABLE escape in a

display drivers affects all windows that are displayed. Because

changing the color table can adversely affect the appearance of

standard window attributes, such as the caption bar or window frame,

using this functionality is not recommended. SETCOLORTABLE should be

used only after considering how it will affect the user interface for

all applications.

The Windows Device Driver Kit (DDK) provides sample code and tools

required to create a new device driver, or to modify an existing

device driver to support the SETCOLORTABLE escape.

Microsoft has also made available a special version of the VGA driver

that implements the SETCOLORTABLE escape. This driver is called

VGAPAL.DRV; it can be found in the Windows Driver Library (WDL), which

is available in the Software Library. For more information on the WDL,

search in the Microsoft Knowledge Base on the following word:

   wdl.txt

Drivers in the WDL can be licensed for redistribution. For more

information, contact Microsoft Product Support Services.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPal


wsprintf() %s Parameters Not Cast to LPSTR

Article ID: Q64759

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

Unrecoverable application errors (UAEs) can result from improperly

using the wsprintf() function. Any parameter passed to wsprintf() that

corresponds to an %s format string MUST be cast to a LPSTR.

The documentation for wsprintf() in the "Microsoft Windows Software

Development Kit Reference Volume 1" states:

   Sequence        Meaning

   ----------------------------------------------------------------

   s               Insert a string argument referenced by a long

                   pointer. The argument corresponding to this

                   sequence MUST be passed as a long pointer (LPSTR).

Wsprintf() is a function with a variable number of parameters. Therefore,

it must be prototyped using the following C calling convention for a

variable number of arguments:

   int FAR cdecl wsprintf(LPSTR, LPSTR,...);

Because the only type information in the prototype describes the output

buffer and the format string, the C compiler cannot perform implicit casts

on the other parameters at compile time. Normally, when a near pointer

(char *) is used as an argument to a function requiring a LPSTR, the

compiler will implicitly cast the (char *) to LPSTR, or (char far *).

Because the compiler cannot cast any of the additional parameters, in

small and medium model programs, any string pointer that is not

explicitly cast FAR will be passed to wsprintf() as a near pointer.

wsprintf() attempts to retrieve a far pointer from the stack, which

results in an invalid pointer and an unrecoverable application error.

The following two code fragments show incorrect and correct usage of

%s fields within wsprintf():

//INCORRECT use of a near pointer. Assume small or medium model.

    {

    char        sz[30];      //sz is a NEAR pointer.

    char        szOut[50];   //szOut is also NEAR

    LPSTR       szFar = sz;  //szFar is FAR

        .

        .

        .

    /*

     * Because it is the output buffer, szOut is implicitly cast to a

     * LPSTR. However, sz is pushed on the stack as a NEAR pointer,

     * which wsprintf will pop as a FAR pointer.

     * This call will cause a UAE.

     */

    wsprintf(szOut, "sz=%s", sz);

    /*

     * This call will succeed since szFar is already a LPSTR.

     */

    wsprintf(szOut, "sz=%s", szFar);

        .

        .

        .

    }

//CORRECT--

    {

    char        sz[30];      //sz is a NEAR pointer.

    char        szOut[50];   //szOut is also NEAR

    LPSTR       szFar = sz;  //szFar is FAR

        .

        .

        .

    /*

     * Because it is the output buffer, szOut is implicitly cast to a

     * LPSTR. Due to the explicit cast, sz is pushed on the stack

     * as a FAR pointer.  This call will succeed.

     */

    wsprintf(szOut, "sz=%s", (LPSTR)sz);

    /*

     * This call will succeed since szFar is already an LPSTR.

     * The cast is redundant, but it's free insurance.

     */

    wsprintf(szOut, "sz=%s", (LPSTR)szFar);

        .

        .

        .

    }

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDrw


Using SetDIBitsToDevice() with a Memory Device Context

Article ID: Q66595

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The SetDIBitsToDevice() function will set the device-independent bitmap

(DIB) only to a physical device context, not to a memory device context. To

set the DIB to a memory device context, use SetDIBits(), or call

StretchDIBits() and specify the same height and width for both the source

and the destination.

It is important to keep in mind that, on a palette device, the palette must

be set appropriately before transferring the image. The SetDIBitsToDevice()

and StretchDIBits() functions do not set the palette automatically. To do

this, perform the following steps:

1. Get the palette from the DIB.

2. Create a logical palette with the palette colors from the DIB.

3. Select the palette into the device context.

4. Realize the palette.

5. Call SetDIBitsToDevice() or StretchDIBits() to transfer the image

   to the device context.

Additional reference words: 3.00 3.10 DC

KBCategory: kbprg

KBSubcategory: GdiBmp


Windows Metafile Functions & Aldus Placeable Metafiles

Article ID: Q66949

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Many Windows-based applications import or export Windows metafiles in a

format known as the Aldus Placeable Metafile (APM) format. In this

format, these metafiles cannot be used with the Windows metafile

functions such as GetMetaFile(), CopyMetaFile(), PlayMetaFile(), etc.

To use these metafiles, the APM header must be removed from the

metafile and the remaining metafile bits must be written to a newly

created metafile.

MORE INFORMATION

================

The APM header is 22 bytes in length and is defined as follows:

typedef struct

  {

  DWORD   key;

  HANDLE  hmf;

  RECT    bbox;

  WORD    inch;

  DWORD   reserved;

  WORD    checksum;

  } APMFILEHEADER;

The following code fragment demonstrates how to create a memory-based

Windows metafile from an Aldus Placeable Metafile that will work with

the metafile functions provided by Windows.

More information regarding the APM format is available from the Aldus

FAX Info System via a fax machine telephone at (206) 628-5737. It will

ask for the document number, which is 9108 for the APM format. It will

then ask you to push start on your FAX machine.

The Placeable Windows Metafiles are also documented on pages 26-27 of the

"Programmer's Reference, Volume 4: Resources" manual from the Windows 3.1

SDK documentation.

NOTE: This an open line and no registration fees are required.

The phone number for Aldus Technical Information is (206) 628-2040.

BOOL RenderAPM (fh)

int   fh; // a file handle to the APM metafile is passed in

{

    HANDLE           hData;

    LPSTR            lpData;

    DWORD            OffsetToMeta;

    METAHEADER       mfHeader;

    APMFILEHEADER    APMHeader;

    OffsetToMeta = sizeof(APMHeader);

// Seek to beginning of file and read APM header

    _llseek(fh, 0, 0);

    if (!_lread(fh, (LPSTR)&APMHeader, sizeof(APMFILEHEADER)))

        // Error in reading the file

        return(FALSE);

// Return to read metafile header

    _llseek(fh, OffsetToMeta, 0);

    if (!_lread(fh, (LPSTR)&mfHeader, sizeof(METAHEADER)))

        // Error in reading

        return(FALSE);

// Allocate memory for memory based metafile

    if (!(hData = GlobalAlloc(GHND, (mfHeader.mtSize * 2L))))

        return(FALSE);

// Were we successful?

    if (!(lpData = GlobalLock(hData)))

    {

        // Error in allocation

        GlobalFree(hData);

        return(FALSE);

    }

// Read metafile bits

    _llseek(fh, OffsetToMeta, 0);

    if (!_lread(fh, lpData, (mfHeader.mtSize * 2L)))

    {

        // Error in reading

        GlobalUnlock(hData);

        GlobalFree(hData);

        return(FALSE);

    }

// Create the METAFILE with the bits we read in.

    if (!(hMF = SetMetaFileBits(hData)))

        return(FALSE);

    GlobalUnlock(hData);

// Close the APM file

    _lclose(fh);

// Return success

    return(TRUE);

}

Additional reference words: 3.00 3.10 CloseMetaFile CopyMetaFile

CreateMetaFile EnumMetaFile GetMetaFile PlayMetaFile PlayMetaFileRecord

SetMetaFileBits SetMetaFileBitsBetter

KBCategory: kbprg

KBSubcategory: GdiMeta


Playing a Metafile into Another Metafile in Windows

Article ID: Q66950

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Unlike Windows versions 2.x, versions 3.0 and 3.1 of Microsoft Windows

permit an application to play a metafile into another metafile. Under

Windows 3.0, the destination metafile must be a disk-based metafile.

This restriction has been removed from Windows 3.1.

MORE INFORMATION

================

Under Windows 3.0, playing a metafile into a new memory metafile

fails. The following is a code fragment that demonstrates the correct

procedure for successfully playing a metafile into a new, disk-based

metafile that is compatible with both Windows 3.0 and 3.1.

// declare variables

   HANDLE hDestDC, hSrcHmf;

// get a handle to the source metafile

   hSrcHmf = GetMetaFile((LPSTR)"SOURCE.WMF");

// create a disk-based destination metafile

// NOTE: The parameter cannot be NULL.

//       That would create a memory metafile.

   hDestDC = CreateMetaFile((LPSTR)"DEST.WMF");

// play the source metafile into the newly created metafile

   PlayMetaFile(hDestDC, hSrcHmf) ;

// get rid of the source metafile

   DeleteMetaFile(hSrcHmf) ;

// close the destination metafile

   hSrcHmf = CloseMetaFile(hDestDC) ;

At this point, the handle to the destination metafile can be used, or

it can be deleted and retrieved later when it is needed.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiMeta


Using a Fixed-Pitch Font as the System Default

Article ID: Q68114

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In versions of Microsoft Windows earlier than version 3.0, the system

font is fixed pitch; beginning with Windows version 3.0, the system

font is proportional. This change can causes difficulties when

applications developed for earlier versions of Windows are moved to

version 3.0. Below is an explanation of how to use a fixed-pitched

font as the system default. Because this technique affects all

applications in the system, however, it should be used with caution.

MORE INFORMATION

================

To change the default system font to any value, modify the fonts.fon=

entry in the [boot] section of the SYSTEM.INI file. The module name of

any font listed here, specified in the module definition (DEF) file

for the font dynamic-link library (DLL) must be FONTS. If the font DLL

has a different module name, Windows does not boot, and the debugging

version of Windows displays a FatalExit (RIP) code of 0x0401 on the

debugging monitor or terminal.

Therefore, to take advantage of this technique, create a custom font

with the proper module name. Install the font and modify the

SYSTEM.INI file so that Windows uses that font as the system default.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiFnt


Windows 3.x Metafiles Support DeleteObject()

Article ID: Q68296

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In versions of Microsoft Windows earlier than 3.0, a metafile that

used a large number of brushes or pens could cause the GDI data

segment to fill up, which would interfere with playing the metafile.

To address this situation, metafiles were extended to support the

DeleteObject() API in Windows 3.0.

Standard Windows programming practice dictates that a GDI object, such

as a brush or a pen, must be deleted by DeleteObject() when the object is

no longer required by an application. This same practice also applies to

metafiles. When an application is drawing into a metafile display context

(DC) and the application no longer requires a GDI object, the application

must select the object out of the metafile DC, then call DeleteObject(). An

example of this process is provided below.

During the process of creating a metafile, when an object is deleted,

Windows inserts a DeleteObject() record into the metafile. When an

application plays the metafile, the DeleteObject() record removes

unnecessary objects, which prevents the GDI data segment from filling.

Note that if an application calls DeleteObject() for an object that is

selected into a metafile DC, the DeleteObject() call will succeed.

However, no DeleteObject() record will be placed into the metafile.

MORE INFORMATION

================

The following code demonstrates the proper method to use and delete

GDI objects in a metafile:

HPEN hPen1, hPen2;

HDC hMetaDC;     // Metafile DC, assumed already created.

hPen1 = CreatePen(PS_SOLID, 6, RGB(0, 0, 255));

SelectObject(hMetaDC, hPen1);          // Select pen into Metafile DC.

Rectangle(hMetaDC, 10, 10, 100, 100);  // Use hPen1.

hPen2 = CreatePen(PS_SOLID, 6, RGB(255, 255, 0));

SelectObject(hMetaDC, hPen2);          // Deselect hPen1 by selecting

                                       // a new pen into the DC.

DeleteObject(hPen1);                   // Delete hPen1.

Rectangle(hMetaDC, 100, 100, 150, 150);  // Use hPen2.

// The metafile is now complete. To deselect the final pen,

// select in a stock object.

SelectObject(hMetaDC, GetStockObject(WHITE_PEN));

// Delete hPen2

DeleteObject(hPen2);

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiMeta


Performance Differences Between LineTo() and Polyline()

Article ID: Q68574

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

When an application must draw a large number of lines, the Polyline()

function will execute 1.1 to 1.5 times faster than the equivalent

calls to the LineTo() function on video hardware that does not have a

graphics coprocessor (such as EGA and VGA). On hardware with a

graphics coprocessor (such as an 8514/A), Polyline() can execute up to

12 times faster than LineTo().

In general, Polyline() is faster than LineTo(). This is magnified by

drawing a very large number of lines. With a small number of lines,

the difference in duration of the calls is negligible compared to the

time required to draw the lines.

MORE INFORMATION

================

LineTo() and Polyline() both use the same internal code to draw lines,

but with slightly different setup procedures.

Polyline() calls GlobalAlloc() and copies all points into that memory;

as a result, there is some overhead. A pointer to the memory is passed

to an internal function that draws all the lines.

LineTo() essentially builds one point and calls the same internal

function as Polyline(). LineTo() does not allocate additional memory.

Polyline() is much more efficient for a large number of lines, since

an application makes a single call to Windows and setup is only

performed once. A large number of calls to LineTo() introduces

significant overhead to make each call and repeatedly execute the

setup code in LineTo().

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDrw


Obtaining Support for Adobe Type Manager (ATM)

Article ID: Q68802

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Microsoft does not address any programming or user questions regarding the

Adobe Type Manager (ATM). Registered owners of ATM can obtain support by

calling (408) 986-6530. The Adobe technicians are prepared to respond to

programming and user questions.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiFnt


PRB: SDK Sample Applications Use Incorrect Background Brush

Article ID: Q71146

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Many of the sample applications that come with the Windows Software

Development Kit (SDK) use a stock object white brush for the window

background color. When the system background color is changed through the

Control Panel, the backgrounds of these sample applications do not change

along with the other applications.

RESOLUTION

==========

To correct this problem, change the value of the hbrBackground field in the

WNDCLASS structure from GetStockObject(WHITE_BRUSH) to COLOR_WINDOW+1. The

background of each modified sample will change with that of every other

Windows-based application.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPnbr


ExtTextOut() Instead of TextOut() to Improve Performance

Article ID: Q71230

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

If speed is the most critical factor when an application writes text

to a window, then the application should take advantage of every

possible speed improvement no matter how minor. Therefore, when

writing text to a window in a time-constrained environment,

ExtTextOut() should be used instead of TextOut() because ExtTextOut()

is slightly faster.

ExtTextOut() is the lowest level function that an application can call

to output text to a window. On the other hand, TextOut() is

essentially a call to ExtTextOut() with wOptions, lpRect, and lpDx set

to zero. Using ExtTextOut() may not result in a noticeable speed

difference; however, it is the faster alternative especially when the

application has a large amount of text to write.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDrw


Font Rotation Under Microsoft Windows

Article ID: Q72021

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In versions of Microsoft Windows earlier than version 3.1, only the

stroke fonts supplied with the Windows graphical device interface

(GDI) are guaranteed to support rotation. Windows 3.1 introduces

TrueType fonts, which also support rotation. Certain raster fonts and

device fonts support rotation also; however, an application that

rotates fonts on a variety of hardware should use a TrueType font or a

GDI stroke font.

MORE INFORMATION

================

Windows supports five types of fonts: GDI raster, GDI stroke, device

raster, device stroke, and TrueType. The Windows GDI provides the

first two font types, the hardware device or device driver provides

the second two font types, and the TrueType rasterizer in Windows 3.1

GDI provides TrueType fonts.

A raster font is a set of bitmaps that represent the different glyphs

(characters) of the font. A raster font is device-specific because

HARDWARE devices differ in aspect ratio and resolution. Windows does

not support rotating a raster font to an arbitrary angle because the

fonts are specific to a device. Windows provides a number of GDI

raster fonts, including MS Sans Serif and MS Serif (respectively

called Helv and TmsRmn in versions of Windows earlier than 3.1).

The glyphs in both stroke fonts and TrueType fonts are stored as

mathematical formulas that describe the direction and length of each

line and arc. Therefore, these fonts are device-independent and

appropriate for any aspect ratio, resolution, or rotation. Windows can

rotate GDI stroke fonts and TrueType fonts. Three stroke fonts are

provided with Windows: Modern, Script, and Roman. Windows 3.1 also

includes a number of TrueType fonts, including Arial and Courier New.

An application can determine the attributes of a given font through

three Windows functions: EnumFonts, EnumFontFamilies, and

GetTextMetrics. When an application uses the EnumFont or

EnumFontFamilies function, it defines a callback function that Windows

calls with the attributes of each enumerated font. The FontType

parameter of the callback function indicates the font's type. When an

application calls the GetTextMetrics function, Windows returns a

TEXTMETRIC data structure containing font attributes. The

tmPitchAndFamily field provides the font type.

Some hardware devices can rotate a raster font. To determine whether a

device can rotate characters (above and beyond what Windows GDI does),

call the GetDeviceCaps function with the TEXTCAPS parameter.

Additional reference words: 3.00 3.10 True Type

KBCategory: kbprg

KBSubcategory: GdiFnt


Baseline Shifts in Cell When Character Italicized

Article ID: Q72460

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

NOTE: With TrueType fonts in Windows 3.1, this process described below is

not necessary. An application should do a version check to determine if it

is running under version 3.0 and perform this process only if the

application is indeed running under Windows 3.0 or if the application is

using non TrueType fonts in Windows 3.1.

SUMMARY

=======

When a font is italicized under Windows version 3.0, the dimensions of the

character cells change because the descender of the character may require

more space at the left edge of the character cell.

Because the character cell is larger, the relative position of the baseline

of the character within the cell changes. The baseline itself is not

affected, but when a character is drawn italic and nonitalic with the

TextOut() function at the same x coordinate, the baseline of the italic

font is shifted a few pixels to the right.

To account for this shift, calculate the slope of the font -- ascent

divided by overhang -- after italicization. Using this slope, the number of

pixels by which the character cell was expanded left is equal to descent

divided by slope, or (descent times overhang) divided by ascent. This value

can be subtracted from the x coordinate in the TextOut() call to align the

baselines.

MORE INFORMATION

================

Consider the character "f". In a normal character cell, it would

appear as:

          ^ ........

          | ........

          | ...xx...

          | ..x..x..

    Ascent| ..x.....

          | ..xx....

          | ..x.....

          | ..x.....

          | ..x.....

          v .xxx....<-baseline

   Descent^ ........

          v ........

When italicized, the descent is shifted to the left and the ascent is

shifted to the right, along a line of constant slope equal to the

ascent divided by the overhang:

          ^ ............

          | ............

          | .......xx...

          | ......x..x..

    Ascent| .....x......

          | .....xx.....

          | ....x.......

          | ....x.......

          | ...x........

          v ..xxx.......<-baseline

   Descent^ ............

          v ............

                     <->

                      Overhang

Because the descent of the character is shifted left according to the

slope of the line, this particular character cell has been expanded

one pixel left, which has the effect of shifting the baseline in the

character cell one pixel right.

Since the overhang represents the amount the ascent of the character

is shifted right in the cell, the corresponding shift of the descent

can be calculated and can be called the "underhang":

                descent * overhang

   underhang = --------------------

                      ascent

When calling the TextOut() function, use the normal x-coordinate where

the text should be drawn, but subtract the underhang. This places the

baseline of the character exactly where it would be if the character

were not italic.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiFnt


Banding, Printing, and the Number of Bands

Article ID: Q72691

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Banding is a printing technique used to print full-page graphics on raster

devices such as dot-matrix printers. In banding, an application prints an

image by dividing the image into several bands (or slices) and sending each

band to the printer separately.

To properly implement banding, an application should never make assumptions

about the number, size, or the ordering of bands that will be provided by a

printer driver. Making assumptions can cause problems because these values

can vary depending on the amount of free memory that is available and the

printer driver that is being used. The correct method for determining the

size and the starting position of bands is to call the escape function

NEXTBAND. This escape function takes as a parameter a LPRECT, which points

to a data structure that will receive the coordinates of the next band. The

NEXTBAND escape function sets the band rectangle to the empty rectangle

when printing reaches the end of the page.

For more information on the NEXTBAND escape function, see pages 12-39 and

12-40 of the Microsoft Windows SDK "Reference Volume 2" or page 489 of the

Windows SDK "Programmer's Reference, Volume 3: Messages, Structures, and

Macros" manual for version 3.1.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Icon and Cursor Size Determined by Display Driver

Article ID: Q73674

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The display driver determines the display size of an icon or a cursor.

Display drivers for Microsoft Windows operating system version 3.0

specify icon- and cursor-compression factors, which are used to

determine the size for a particular icon or cursor. Under Windows

version 3.1, the method that the display driver uses for storing icon

and cursor dimensions is different. The text below details the two

methods of storing icon and cursor dimensions.

MORE INFORMATION

================

Each compression factor is the ratio of 64 to the icon or cursor size.

In other words, the icon-width compression factor is 64 divided by the

final width of an icon. Because each factor must be a whole number,

the height or the width of an icon or a cursor must be 64, 32, or 16

pixels.

Four compression factors are stored as a resource in each display

driver. The following table shows typical values:

   Display             Icon/Cursor        Compression Factors

   Drivers             Dimensions         Width       Height

   ----------------------------------------------------------

   CGA                  32 x 16             2           4

   EGA, VGA, 8514       32 x 32             2           2

In Windows version 3.1, the display driver stores the actual icon

dimensions. Therefore, for an icon 32 pixels wide, the driver stores

32 instead of 2. This removes the limitation that 64 by 64 is the

largest possible icon size.

Display drivers for versions of Windows earlier than version 3.0 will

continue to be supported. If Windows encounters an icon dimension less

than 11, it treats the dimension as a compression factor and

calculates the dimension accordingly.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiCurico


Logical and Physical Coordinate Relationship

Article ID: Q74044

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows is designed to use a logical coordinate system when doing many of

its graphics operations. Many of the Windows functions take logical units

as parameters. Windows translates these units to physical device units

based on the mapping mode of the device, window origin, window extents,

viewport origin, and viewport extents.

This article discusses the relationship between logical and physical

coordinates.

MORE INFORMATION

================

The default mapping mode for a device context (DC) is the MM_TEXT mode. The

point (0,0) is the origin of the logical and physical coordinate systems in

this mode. It also has a 1 to 1 mapping ratio of logical to physical device

units.

The programmer can change the mapping mode of a DC by using the

SetMapMode() function.

The following six mapping modes have predefined logical to physical mapping

ratios:

 - MM_TEXT

 - MM_LOENGLISH

 - MM_HIENGLISH

 - MM_LOMETRIC

 - MM_HIMETRIC

 - MM_TWIPS

The following two mapping modes can be set to have user defined ratios

of logical to physical units:

 - MM_ANISOTROPIC

 - MM_ISOTROPIC

In the last two modes, coordinates are transformed from logical to physical

and vice versa based on the current window and viewport extents in the DC.

The functions SetWindowExt() and SetViewportExt() allow an application to

set the window and viewport extents. These functions should only be used in

the MM_ANISOTROPIC and MM_ISOTROPIC mapping modes because they are the only

ones in which the application can define the mapping ratio.

The formulae used to convert to and from the different coordinate systems

are documented in section 2.5.3, page 2-18, in the "Microsoft Windows

Software Development Kit Reference Volume 1" for version 3.0.

REFERENCES

==========

For more information about the relationship between the logical and

physical planes, refer to the following:

"Microsoft Windows Software Development Kit Reference Volume 1"

version 3.0, section 2.5 "Mapping Functions," pages 2-15 through 2-20.

"Programming Windows," first edition, by Charles Petzold

  Chapter 12, pages 520-540.

"Programming Windows," second edition, by Charles Petzold

  Chapter 11, pages 517-539.

"Peter Norton's Windows 3.0 Power Programming Techniques," by Peter

  Norton and Paul Yao, Chapter 20, c. 1990, Bantam Books.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDc


Microsoft Windows Caches Five Display Contexts

Article ID: Q74291

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The Microsoft Windows graphical environment maintains an internal

cache of five display contexts (DCs) which are shared by all

applications in the system. An application retrieves one of these DCs

when it calls the BeginPaint(), GetDC(), or GetWindowDC() functions. When

an application retrieves a DC, Windows marks the DC as in use and does

not allow another application to retrieve it. When an application has

finished using a DC, it must return the DC to the cache which makes

the DC available to another application. Two APIs return a DC to

the cache: EndPaint() function (to match BeginPaint()) and the

ReleaseDC() function (to match GetDC() or GetWindowDC()).

If an application fails to return DCs to the DC cache correctly, the

cache becomes empty, and subsequent calls to BeginPaint(), GetDC(), and

GetWindowDC() fail. Because most applications do not check to be sure

that the DC they retrieve is valid, they attempt to use an invalid DC

in a graphics device interface (GDI) call, which causes a FatalExit

error.

To avoid this problem, be sure to return DCs to the cache correctly

and check the value returned by BeginPaint(), GetDC(), and GetWindowDC() to

ensure that a valid DC is available.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDc


Charts and Graphs for Windows-Based Applications

Article ID: Q74560

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

Chapter 11 of the book "Microsoft C Advanced Programming Techniques,"

included with the Microsoft C Compiler version 6.0 discusses creating

charts and graphs in MS-DOS using the C presentation graphics library

PGCHART.LIB.

Windows does not include a presentation graphics library as such, but

the Windows graphics functions can be used to draw graphs and charts.

PGCHART.LIB is only for use with MS-DOS-based applications.

Page 570 of Charles Petzold's "Programming Windows" (Second Edition)

includes an example of using the Windows Pie() function to draw a pie

chart. Similarly, other GDI functions, such as Rectangle(), Polygon(),

or LineTo(), could be used to draw charts or graphs.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiDrw


Using GetDIBits()

Article ID: Q74601

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

GetDIBits() retrieves the bits of a specified bitmap and copies them, in

device-independent format, into the buffer that is specified in the lpBits

parameter. If the lpBits parameter is NULL, GetDIBits fills in the

BITMAPINFO data structure to which the lpBitsInfo parameter points, but

does not retrieve bits from the bitmap. The application must ensure that

the BITMAPINFO data structure passed in the GetDIBits call contains valid

data before making the GetDIBits call. This article describes how Windows

verifies that the data in the BITMAPINFO structure is valid.

MORE INFORMATION

================

When NULL is specified as the lpBits parameter of GetDIBits, the function

will ensure that the structure passed in to it contains valid data. Then,

the function sets the biSizeImage field of the BITMAPINFOHEADER structure

and the bmiColors field of the BITMAPINFO structure.

To validate the BITMAPINFO structure, the following list outlines the

checks that are made:

   biSize == sizeof(BITMAPINFOHEADER)

   biHeight: high word is 0

   biWidth: high word is 0

   biPlanes == 1

   biBitCount == 1, 4, 8, or 24

   biCompression: high word is 0

   biCompression: low word is 0, BI_RLE8, or BI_RLE4

   if biCompression == BI_RLE8: biBitCount == 8

   if biCompression == BI_RLE4: biBitCount == 4

NOTE: For Windows 95 and Windows NT, the following line

   biBitCount == 1, 4, 8, or 24

should be changed to:

   biBitCount == 1, 4, 8, 16, 24, or 32

All these conditions must be true if GetDIBits is to function correctly and

return valid data (either by setting the biSizeImage field or by returning

the DIB's bits).

If any of these conditions is not true, the header is invalid, and

GetDIBits returns 0 (zero).

GetDIBits is performed on the device driver level. Because different

devices may use different formats to store data, only the device knows its

particular format. Thus, it is the responsibility of the driver to convert

the device format to a device-independent format. If the device driver is

not completely reliable, then GetDIBits may return erroneous information.

This should be considered when using GetDIBits.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiBmp


Supporting PostScript Features in Windows

Article ID: Q74704

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

There are some issues involved when designing an application to

provide support for PostScript printers. The application must

determine if the PostScript driver is available by using an accurate

detection system. If an application generates PostScript directly, the

PASSTHROUGH escape can be used to send the file. This must be done

with care because the application is communicating directly with the

printer.

MORE INFORMATION

================

The first issue is how to determine if a PostScript driver is an

installed printer driver under Windows. An application cannot assume

the PostScript driver is named PSCRIPT.DRV because this forces

PostScript driver vendors to use the same filename. The correct method

is to run code similar to the pseudocode below:

   bFound = FALSE;

   for (each device in [Devices] section of win.ini) {

        /* extract the necessary fields from the ini line */

        szDriverName = driver name extracted from ini line

        szModelName = left side of ini line (the key)

        szPort = port name extracted from ini line.

        hIC = CreateIC(szDriverName, szModelName, szPort, NULL);

        if (hIC) {

                /* see if driver supports GETTECHNOLOGY escape */

                wEscape = GETTECHNOLOGY;

            if (Escape(hIC, QUERYESCSUPPORT, sizeof(WORD), &wEscape, NULL))

{

                          Escape(hIC, GETTECHNOLOGY, 0, NULL,

&szTechnology);

                         /* Check that the string starts with PostScript

                          * by doing a case-insensitive search. Allow

                          * for the possibility that the string could be

                          * longer, like "PostScript level 2" or some other

                          * extension.

                          */

                         if (beginning of string is "PostScript")

                                 bFound = TRUE;

                }

                DeleteDC(hIC);

        }

        /* if the driver has been found break out */

        if (bFound)

                break;

   }

   if (bFound) {

        PostScript driver is szDriverName, model is szModelName, port is

        szPort.

   }

NOTE: In the event that GETTECHNOLOGY is not supported by some printer

drivers, another method need to be used to determine if the printer is

a PostScript printer. One possible method is to use QUERYESCSUPPORT on

escapes that are only implemented by PostScript printers. For example:

   EPSPRINTING

   SETLINEJOIN

   SETMITERLIMIT

   SET_POLY_MODE

Similarly, you can determine a PCL printer by calling QUERYESCSUPPORT

on the following escape:

   DRAWPATTERNRECT

The second issue is how to print application-generated PostScript

code. The mechanism from a Windows-based application is through the

PASSTHROUGH escape. The PASSTHROUGH escape is documented in the

"Microsoft Windows Software Development Kit Reference Volume 2,"

Chapter 12. In addition to the documentation, one requirement on the

buffer passed is easy to miss; the first word must contain the length

of the buffer. The contents of the data sent by PASSTHROUGH can alter

the state of the printer.

To be safe, obey the following rules:

1. Surround PASSTHROUGH data by save/restore PostScript operators.

2. Do not embed GDI calls between PASSTHROUGH escapes. For example:

      PASSTHROUGH(save)

      Rectangle

      OtherGDIRoutines

      PASSTHROUGH(restore)

   Some driver code and software fonts are downloaded to the printer

   under certain conditions. The above operations could cause the

   driver and printer to loose synchronization, and potentially cause

   the job to fail. In general, no assumptions should be made

   concerning the code generated by a given GDI call.

3. Do not send a command to cause a page ejection.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Steps to Send a Document to a Printer

Article ID: Q75339

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

If code simplicity is more desirable than printing efficiency, an

application can implement printing with almost no additional code. For

this discussion, the application defines a DrawStuff procedure that renders

text and/or graphics into a specified display context. The application can

render the image to the screen by getting a screen display context and

passing its handle to DrawStuff(). Printing is more involved; the seven

steps required are detailed below.

1. Use GetProfileString() to get the printer driver name and port to print

   to from the WIN.INI file. Specify "windows" as the application and

   "device" as the key name.

2. Call the CreateDC() to get a display context for the printer.

The following code demonstrates these two steps:

     //

     // HDC GetPrinterDC(void)

     //

     // Return a DC to the currently selected printer.

     // Returns NULL on error.

     //

     HDC GetPrinterDC(void)

     {

        static char szPrinter[64];

               char *szDevice, *szDriver, *szOutput;

        GetProfileString("windows", "device", "", szPrinter, 64);

        if ((szDevice = strtok(szPrinter, "," ))

              && (szDriver = strtok(NULL, ", "))

              && (szOutput = strtok(NULL, ", ")))

           return CreateDC(szDriver, szDevice, szOutput, NULL);

        return NULL;

     }

3. Use the STARTDOC Escape to start a print job. [In Windows 3.1 and later,

   call the StartDoc() function rather than the STARTDOC escape.]

     szJobName = "<job name>";

     Escape(hDC, STARTDOC, lstrlen(szJobName), szJobName, NULL);

   [3.5. In Windows 3.1 and later, call StartPage() to begin a page.]

4. Draw the page by calling DrawStuff(hDC).

5. Use the NEWFRAME Escape to start the next page. [In Windows 3.1 and

   later, call the EndPage() function rather than the NEWFRAME escape.]

     Escape(hDC, NEWFRAME, 0, 0L, 0L);

   (If more than one page is printed, repeat steps 4 and 5 for each page.)

6. Use the ENDDOC Escape to end the print job. [In Windows 3.1 and

   later, call the EndDoc() function rather than the ENDDOC escape.]

     Escape(hDC, ENDDOC, 0, 0L, 0L);

7. Call DeleteDC() to free the printer display context.

     DeleteDC(hDC);

Printing requires little extra work if the drawing code is modular. The

drawback to the approach above is that it can require more memory and

printing time than may otherwise be necessary. For more information on

speeding the printing process, query on the following words in the

Microsoft Knowledge Base:

   prod(winsdk) and printing and banding

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


PRB: Available Memory Decreases When Print Job Terminated

Article ID: Q75430

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When a print job is terminated, the amount of available memory reported in

the Program Manager's About box declines. This indicates that allocated

memory objects remain on the global heap.

CAUSE

=====

One possible cause is an application that calls the print job abort

procedure directly through its instance thunk. If, after this call,

the print job is aborted and the application exits its printing loop

without calling the ABORTDOC printer escape, the print job will not be

properly aborted and allocated memory will be left on the heap.

RESOLUTION

==========

The abort procedure returns FALSE if the print job has been aborted. If the

abort procedure returns FALSE, the application should call the ABORTDOC

printer escape in Windows 3.0 or AbortDoc() in Windows 3.1. The following

code fragment demonstrates this procedure:

   // Call the Abort procedure

   if (!(*lpfnAbortProc)(hDC, 0))

       Escape(hDC, ABORTDOC, NULL, NULL, NULL);

MORE INFORMATION

================

An application registers its printing abort procedure with Windows by

calling the SETABORTPROC escape in Windows 3.0 or SetAbortProc() in Windows

3.1. Windows automatically calls the abort procedure during the NEWFRAME or

NEXTBAND escape. If the print job is aborted during the NEWFRAME or EXTBAND

escape, Windows automatically calls the ABORTDOC escape/AbortDoc().

If the print job is aborted when the application has called the abort

procedure directly, the application must call the ABORTDOC escape/

AbortDoc().

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


Windows, Code Pages, and Character Sets

Article ID: Q75435

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0

----------------------------------------------------------------------

SUMMARY

=======

The ASCII (American Standard Code for Information Interchange)

character set defines a mapping of the letters, numerals, and

specified punctuation and control characters to the numbers from zero

to 127. The term "code page" is used to refer to extensions of the

ASCII character set that also map specified symbols to the numbers

from 128 through 255.

This article discusses how Windows deals with code pages and warns

against some of the pitfalls that applications can encounter.

MORE INFORMATION

================

The ANSI (American National Standards Institute) character set maps

the letters and numerals in the same manner as ASCII. However, ANSI

does not support control characters and it maps many symbols,

including accented letters, that are not mapped in standard ASCII. All

Windows fonts are defined in the ANSI character set.

An OEM (original equipment manufacturer) code page is built into the

computer hardware. There are a number of OEM code pages, each defined

for a particular language. These code pages are referred to by a

number; for example, code page 437 is installed in the original IBM PC

computer.

MS-DOS uses code pages to change the available character set, depending

on user preference. A code page change is implemented by programming a

new character set into the video display hardware. By changing to the

code page for a particular language, the accented characters

appropriate to that language are made available. Each code page is

limited to 256 symbols.

For each code page, MS-DOS maintains a mapping table to map lowercase

characters to and from uppercase. Because all string parameters to

MS-DOS (filenames) are implicitly coded in the current code page,

when the table is changed, filenames that were accessible under one

case mapping may not be available under another. However, the common

code pages were designed to combat this problem.

Windows runs as an extension to MS-DOS. There is a mapping layer that

translates between the ANSI character set and an OEM character set.

When Windows is installed, the Setup program determines the installed

character set and installs the corresponding ANSI-OEM translation

tables and Windows OEM fonts.

If the user changes the current MS-DOS code page, Windows does not

change its ANSI-OEM mapping tables automatically. It is necessary to

run the Windows Setup program to modify these tables and to load the

corresponding fonts.

Windows-based applications must use the Windows functions AnsiToOem() and

OemToAnsi() when transferring information to and from MS-DOS. In

addition, applications must use the correct character set when

creating filenames.

There is no one-to-one mapping between the ANSI and OEM character

sets. Applying the AnsiToOem() function followed by the OemToAnsi()

function to a given string will not always result in the original

string. A file that has been named with one of these strings cannot

be accessed by any Windows-based application. The filename must be changed

by the user from outside of Windows.

The following two scenarios may have differing results.

SCENARIO 1

----------

A lowercase ANSI string is passed to the AnsiToOem() function. The

result is passed to MS-DOS, which maps the string to uppercase.

SCENARIO 2

----------

An uppercase ANSI string is passed to the AnsiToOem() function. The

string is passed to MS-DOS.

This is caused by the fact that the MS-DOS lowercase to uppercase

conversion mapping and the Windows ANSI case conversion do not match.

To avoid this problem, use the AnsiUpper() function to convert the

ANSI string to uppercase before passing it to the AnsiToOem()

function. Also note, this is only a problem with extended characters.

These problems are often overlooked until your customers call to

complain.

Keep in mind that both ANSI and OEM are 8-bit character sets. In

applications, always use the "unsigned char" type instead of "signed

char" for character variables. Problems that result from using "signed

char" are very hard to track.

The SYSTEM.INI file contains entries that relate to code pages. In the

[boot] section, the OEMFONTS.FON line specifies the file that contains

the OEM stock font. In the [keyboard] section, the OEMANSI.BIN line

specifies the ANSI-OEM translation table. If this line is blank,

Windows uses the default table built into the keyboard driver. In the

[enh] section, the *WOA.FON lines specify the fonts used in an MS-DOS

window at various resolutions.

Windows does not provide any mechanism for an application to work with

data that is not in the current MS-DOS code page, nor does Windows

recognize changing the OEM code page in an MS-DOS window. However, an

application is free to provide its own translation tables and provide

a data format that includes the code page.

Additional reference words: 3.00

KBCategory: kbprg

KBSubcategory: GdiFnt


Basics of Banding Printing in Windows

Article ID: Q75471

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Banding is a technique used to implement the full functionality of the

Windows graphics device interface (GDI) in printer drivers that can

only print bitmaps for graphics. An application that is aware of the

banding process can enhance its printing performance.

MORE INFORMATION

================

Most dot-matrix printers and many laser printers cannot print graphics

such as polygons and lines. They can print only bitmaps and text.

These printers require special support in GDI to implement the full

range of GDI functionality.

When an application prints to such a device, the printer driver does

not send output directly to the printer. Rather, the printer driver

generates a bitmap in memory. When all graphics have been rendered

into the bitmap, the bitmap itself is printed.

For most printers, the bitmap can be very large. For example, a 300

dots-per-inch (dpi) laser printer requires nearly a megabyte to render

a single letter-size page. To reduce memory requirements, the image is

broken into a sequence of smaller rectangles, called bands, which

cover the page. Each of these individual rectangles is rendered and

downloaded to the printer separately.

There are two ways that the graphics calls can be duplicated on each

band. If the application is unaware of the banding process, GDI will

capture all graphics calls for a page into a metafile. When the

application calls the NEWFRAME (next page) escape, GDI plays the

entire metafile into each band. Alternatively, the application may

request a band from the printer driver and produce the output itself.

A significant optimization results since GDI will not need to create,

write, and reread a disk-based metafile.

Whether GDI or the application requests the band from the driver, the

process is very similar. Banding printer drivers implement an escape

called NEXTBAND. The escape causes the printer driver to download the

previous band to the printer (if any) and to initialize itself to

render the new band. It also returns a rectangle defining the bounds

of the band bitmap relative to the whole page. Output calls made to

the driver's device context (DC) after NEXTBAND go directly to the

printer driver.

GDI, or the banding application, calls NEXTBAND after each band is

rendered to download the band and also to retrieve the next band from

the driver. When all bands have been printed, NEXTBAND causes the

printer driver to eject the page and return an empty rectangle to

indicate the end of a page.

For more information on how to implement banding, query on the

following words:

   prod(winsdk) and banding

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Paper Sizes 50 through 56 Reserved for PostScript Driver

Article ID: Q75911

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Version 3.4 of the PostScript printer driver, distributed with version

3.0 of the Microsoft Windows graphical envionment, implements the

following paper size constants:

   #define DMPAPER_LETTER_EXTRA   50

   #define DMPAPER_LEGAL_EXTRA    51

   #define DMPAPER_TABLOID_EXTRA  52

   #define DMPAPER_A4_EXTRA       53

These constants are specific to the PostScript driver (as is the

entire range from 50 to 56). These constants are used only by

Linotronic printers to help save paper and do not generally apply.

The DRIVINIT.H header file distributed with version 3.0 of the

Microsoft Windows Device Development Kit (DDK) lists these constants

while the DRIVINIT.H file distributed with version 3.0 of the

Microsoft Windows Software Development Kit (SDK) does not. In version

3.1, the PRINT.H header file replaces DRIVINIT.H. PRINT.H contains the

following note:

   Warning: The PostScript driver mistakingly uses DMPAPER_ values

   between 50 and 56. Don't use this range when defining new paper

   sizes.

To avoid conflicts, do not use the range 50-56 when defining new paper

sizes.

MORE INFORMATION

================

The DRIVINIT.H file contains constants (defined with the prefix

DMPAPER_) for all the standard paper sizes. These constants are

usually retrieved from the printer driver by using the ExtDeviceMode

function, and examining the dmPaperSize field. Some PostScript drivers

support the paper sizes listed above, and will return one of the

listed constants if the extra paper size is selected in the

ExtDeviceMode dialog box.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


How to Create Device-Independent Printing Code

Article ID: Q76260

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows provides a device-independent platform for application developers.

Device independence applies to printing as well. To write code to work with

any printer driver, applications must not rely on any special feature in a

printer driver. Instead, applications should direct all requests through

the Windows Graphical Device Interface (GDI).

MORE INFORMATION

================

There are two major classes of printers: raster printers and PostScript

printers. This article is directed towards application support for raster

printers.

With the exception of the standard printer escapes, applications should not

rely on any printer escape to be supported in a particular printer driver.

Note that the printer escapes are supported in Windows 3.1, but it is

recommended that you use the new equivalent functions, instead of the

escapes.

The standard escapes/functions are: STARTDOC/StartDoc(), ENDDOC/EndDoc(),

NEXTBAND, NEWFRAME, SETABORTPROC/SetAbortProc(), and ABORTDOC/AbortDoc().

The remaining escapes are optional for printer drivers. Applications should

use the QUERYESCSUPPORT escape to test for the support of optional escapes.

Applications should not depend on private knowledge of how a particular

driver works.

For example, the DRAWPATTERNRECT escape is available on certain

devices. The following code fragment determines if the DRAWPATTERNRECT

escape is supported on the installed device. If not, an alternative

function, PatBlt(), is used to create the output.

  short i;

  i = DRAWPATTERNRECT;

  if (Escape(hPr, QUERYESCSUPPORT, sizeof(i), (LPSTR)&i, NULL))

      Escape(hPr, DRAWPATTERNRECT, sizeof(lpPatRect),

               (LPSTR)lpPatRect, NULL);

  else

      PatBlt(hPr, .....);

Of the remaining escapes, the following are used frequently:

GETPHYSPAGESIZE, GETPRINTINGOFFSET, PASSTHROUGH, and DRAWPATTERNRECT.

An application should minimize the number of escapes that it uses.

Another area of device independence applies to ExtDeviceMode().

Applications should not allow the user to change printer settings globally.

If the user wants to change the printer settings for all applications, the

Control Panel utility should be used. It is more appropriate for printer

settings to be associated with an application, a document, or a particular

set of pages in a document. For more information please see the Knowledge

Base article

   "Using ExtDeviceMode() to Modify Printer Settings"

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Verifying the Printer Connection

Article ID: Q77467

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The PC ROM BIOS printer services function Get Printer Status (INT 17H

Function 2H) can be used to determine if a printer is connected to a

specific port. To save time and potential data loss, an application

can use INT 17H Function 2H to determine if a printer is present

before entering the application's printing code. This article contains

code to make this determination.

NOTE: This same functionality may be obtained in Windows 3.1 using the

OpenComm(), WriteComm(), and GetCommError() functions.

Sample Code

-----------

The following code defines a function IsPrinter():

 /***************************************************************

  *                                                             *

  *  Name:     IsPrinter - tests if printer is connected        *

  *                                                             *

  *  Parameters:   AX = 02h                                     *

  *                DX = printer number (LPT1 = 0)               *

  *                                                             *

  *  Return    AH = status bits                                 *

  *                 01h    time out                             *

  *                 02h    unused                               *

  *                 04h    unused                               *

  *                 08h    I/O error                            *

  *                 10h    printer selected                     *

  *                 20h    out of paper                         *

  *                 40h    printer acknowledgment               *

  *                 80h    printer not busy                     *

  *                                                             *

  * Function returns 1 if printer connected                     *

  *          returns 0 otherwise                                *

  *                                                             *

  ***************************************************************/

int IsPrinter(void)

{

   unsigned char iRetVal = 0;

   _asm

      {

         mov   ah, 02h

         mov   dx, 0            /* 0 is number for LPT1: */

         int   17h

         mov   iRetVal, ah

      }

   if (iRetVal == 0x90)

      return (1);

   else

      return (0);

}

For more information, please refer to "The MS-DOS Encyclopedia"

(Microsoft Press). Pages 163 and 164 contain an example of interrupt

driven communication with the printer. Appendix O details the ROM BIOS

functions and their parameters.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprint kbcode

KBSubcategory: GdiPrn


Using ExtDeviceMode() with DM_COPY

Article ID: Q77551

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The documentation for the ExtDeviceMode() API does not completely explain

the results of setting the wMode parameter to various values, in particular

the DM_COPY value. This function may produce unexpected results if the

wMode parameter is set incorrectly.

MORE INFORMATION

================

For a complete explanation of the ExtDeviceMode() API, see the

"Microsoft Windows Software Development Kit Guide to Programming,"

in particular, the following paragraph

   IMPORTANT: In order to change the settings, you must specify at

   least one input value and one output value.... If you specify only

   output values (DM_COPY or DM_UPDATE), the driver provides its

   current settings and ignores any input you provide. If you specify

   only input values (DM_MODIFY or DM_PROMPT), calling ExtDeviceMode

   generates no output, so your input has no real effect.

If the wMode parameter is set to DM_COPY only, the printer's default

settings will be copied into the output buffer -- even if an input

buffer is specified.

In some cases, it is necessary to copy the print settings from the

input buffer to the output buffer (for example, to validate some

fields in the structure). To do this, set the wMode parameter to

(DM_COPY | DM_MODIFY).

Note that DM_IN_BUFFER, DM_IN_PROMPT, DM_OUT_BUFFER, and

DM_OUT_DEFAULT are aliases for the DM_MODIFY, DM_PROMPT, DM_COPY, and

DM_UPDATE constants, respectively.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


PRB: Complex Printing Region Printed Incorrectly

Article ID: Q77884

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When an application uses region and clipping functions on a printer

device context (DC) to create a complex printing area, some of the

clipping functions have no effect on the printed page.

CAUSE

=====

The Windows Graphics Device Interface (GDI) is running out of heap space.

RESOLUTION

==========

The application must perform some additional steps to simplify the

drawing. Verify that calculated regions are freed between function calls.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiDc


Detecting EGA.SYS

Article ID: Q78451

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

EGA.SYS is a driver that facilitates the use of the shadow registers in EGA

and more advanced video cards. Through the use of the mouse driver's

Interrogate Driver function, it is possible to determine if EGA.SYS is

installed.

The interface to the Interrogate Driver function is as follows:

   AH = FAh

   BX = 0

   INT 10h

The return values are:

   AX = Restored

   BX = 0 if the mouse driver or EGA.SYS is not installed

      < 2 if EGA.SYS was installed with the mouse driver

     >= 2 if EGA.SYS was installed

For more information, see chapter 10 of the "Microsoft Mouse

Programmer's Reference," second edition (Microsoft Press).

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiMisc


Drawing Transparent Bitmaps

Article ID: Q79212

-------------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows, versions

   3.0 and 3.1

-------------------------------------------------------------------------

SUMMARY

=======

A portion of a graphic image that does not change the contents of the

screen is termed "transparent." The DrawIcon function can create an

image that contains transparent portions. It is also possible to

obtain this functionality using the BitBlt function; however, there

are some additional steps involved.

The first step is to obtain the contents of the area where the bitmap

will be drawn and to store this background image in a memory display

context (DC). Mask out the area of the background that corresponds to

the nontransparent portion of the image bitmap and mask out all

transparent pixels from the image bitmap. Use the XOR raster operation

to merge the image bitmap into the background bitmap. Finally, use the

BitBlt function to move the merged image to the destination DC.

MORE INFORMATION

================

The following nine steps describe a process used to draw transparent

bitmaps:

1. Create a DC to hold the image bitmap.

2. Select the image bitmap into the DC.

3. Create a memory DC to hold the final image. This is the destination

   DC.

4. Copy the portion of the screen that will be covered by the image

   into the destination DC.

5. Create an "AND mask" that contains the mask of the colors to draw

   (the nontransparent portions of the image). To do this, perform

   the following three steps:

   a. Set the background color of the image DC to the color that will

      be transparent in the image.

   b. Create a monochrome DC.

   c. BitBlt the image into the monochrome DC.

   This will create an AND mask of the bitmap by setting pixels that

   match the background color to white (1), and setting all other

   pixels to black (0).

6. Use BitBlt with the SRCAND raster operation code to copy the AND

   mask onto the destination DC.

7. Use BitBlt with the SRCAND raster operation code to copy the

   inverse of the AND mask onto the image DC.

8. Use BitBlt with the SRCPAINT raster operation code to copy the

   image DC onto the destination DC.

9. Use BitBlt to copy the contents of the destination DC to the

   appropriate portion of the screen.

The following code is a function that demonstrates the above steps:

void DrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart,

                           short yStart, COLORREF cTransparentColor)

   {

   BITMAP     bm;

   COLORREF   cColor;

   HBITMAP    bmAndBack, bmAndObject, bmAndMem, bmSave;

   HBITMAP    bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;

   HDC        hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;

   POINT      ptSize;

   hdcTemp = CreateCompatibleDC(hdc);

   SelectObject(hdcTemp, hBitmap);   // Select the bitmap

   GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);

   ptSize.x = bm.bmWidth;            // Get width of bitmap

   ptSize.y = bm.bmHeight;           // Get height of bitmap

   DPtoLP(hdcTemp, &ptSize, 1);      // Convert from device

                                     // to logical points

   // Create some DCs to hold temporary data.

   hdcBack   = CreateCompatibleDC(hdc);

   hdcObject = CreateCompatibleDC(hdc);

   hdcMem    = CreateCompatibleDC(hdc);

   hdcSave   = CreateCompatibleDC(hdc);

   // Create a bitmap for each DC. DCs are required for a number of

   // GDI functions.

   // Monochrome DC

   bmAndBack   = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);

   // Monochrome DC

   bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);

   bmAndMem    = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);

   bmSave      = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);

   // Each DC must select a bitmap object to store pixel data.

   bmBackOld   = SelectObject(hdcBack, bmAndBack);

   bmObjectOld = SelectObject(hdcObject, bmAndObject);

   bmMemOld    = SelectObject(hdcMem, bmAndMem);

   bmSaveOld   = SelectObject(hdcSave, bmSave);

   // Set proper mapping mode.

   SetMapMode(hdcTemp, GetMapMode(hdc));

   // Save the bitmap sent here, because it will be overwritten.

   BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);

   // Set the background color of the source DC to the color.

   // contained in the parts of the bitmap that should be transparent

   cColor = SetBkColor(hdcTemp, cTransparentColor);

   // Create the object mask for the bitmap by performing a BitBlt

   // from the source bitmap to a monochrome bitmap.

   BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,

          SRCCOPY);

   // Set the background color of the source DC back to the original

   // color.

   SetBkColor(hdcTemp, cColor);

   // Create the inverse of the object mask.

   BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,

          NOTSRCCOPY);

   // Copy the background of the main DC to the destination.

   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,

          SRCCOPY);

   // Mask out the places where the bitmap will be placed.

   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);

   // Mask out the transparent colored pixels on the bitmap.

   BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);

   // XOR the bitmap with the background on the destination DC.

   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);

   // Copy the destination to the screen.

   BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,

          SRCCOPY);

   // Place the original bitmap back into the bitmap sent here.

   BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);

   // Delete the memory bitmaps.

   DeleteObject(SelectObject(hdcBack, bmBackOld));

   DeleteObject(SelectObject(hdcObject, bmObjectOld));

   DeleteObject(SelectObject(hdcMem, bmMemOld));

   DeleteObject(SelectObject(hdcSave, bmSaveOld));

   // Delete the memory DCs.

   DeleteDC(hdcMem);

   DeleteDC(hdcBack);

   DeleteDC(hdcObject);

   DeleteDC(hdcSave);

   DeleteDC(hdcTemp);

   }

The following is an example of how the DrawTransparentBitmap function

might be called:

   DrawTransparentBitmap(hdc,         // The destination DC.

                         hBitmap,     // The bitmap to be drawn.

                         xPos,        // X coordinate.

                         yPos,        // Y coordinate.

                         0x00FFFFFF); // The color for transparent

                                      // pixels (white, in this

                                      // example).

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiBmp


Converting Between Device-Dependent Bitmaps and DIBs

Article ID: Q80080

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article explains the basic steps involved in converting between device-

dependent bitmaps (DDBs) and Windows 3.0 style device-independent bitmaps

(DIBs). This article assumes some background knowledge of bitmaps, DIBs,

palettes, and memory allocation.

The SHOWDIB sample application provided in versions 3.0 and 3.1 of the

Windows SDK, the WINCAP sample application available in the Microsoft

Software Library, and the DIBVIEW sample application provided in version

3.1 of the Windows SDK and in the Professional Edition of Visual C++ each

demonstrate the steps described in this article.

MORE INFORMATION

================

Use the following steps to convert a DDB to a DIB:

1. Initialize the BITMAPINFOHEADER data structure.

   a. Set biSize to sizeof(BITMAPINFOHEADER).

   b. Set biWidth to the width of the bitmap.

   c. Set biHeight to the height of the bitmap.

   d. Set biPlanes to 1.

   e. Set biBitCount to the bitmap bmPlanes multiplied by

      bmBitsPixel. This value can contain only the values 1, 4, 8, or

      24.

   f. Set biCompression to the desired format (usually BI_RGB).

   g. All other fields can be set to zero.

   Code to initialize the BITMAPINFOHEADER data structure might look

   like the following:

      BITMAPINFOHEADER bmi;

      BITMAP           bm;

      .

      .

      .

      bmi.biSize          = sizeof(BITMAPINFOHEADER);

      bmi.biWidth         = bm.bmWidth;

      bmi.biHeight        = bm.bmHeight;

      bmi.biPlanes        = 1;

      bmi.biBitCount      = bm.bmPlanes * bm.bmBitsPixel;

      if (bmi.biBitCount <= 1)

        bmi.biBitCount = 1;

      else if (bmi.biBitCount <= 4)

        bmi.biBitCount = 4;

      else if (bmi.biBitCount <= 8)

        bmi.biBitCount = 8;

      else

        bmi.biBitCount = 24;

      bmi.biCompression   = BI_RGB;

      bmi.biSizeImage     = 0;

      bmi.biXPelsPerMeter = 0;

      bmi.biYPelsPerMeter = 0;

      bmi.biClrUsed       = 0;

      bmi.biClrImportant  = 0;

2. If there is a logical palette associated with the bitmap, select

   the palette into the desired device context using SelectObject(),

   then realize the palette with RealizePalette().

3. Allocate a block of memory large enough to store the

   BITMAPINFOHEADER structure and the color table for the DIB. The

   color table is an array of RGBQUAD structures that contain the

   colors used by the image. The size of the color table is the number

   of colors multiplied by sizeof(RGBQUAD). The number of colors is

   found using the biBitCount field in BITMAPINFOHEADER, which

   specifies the color resolution (bits per pixel). For example, 1

   bit-per-pixel means monochrome (2 colors), 4 bits-per-pixel means

   16 colors, and 8 bits-per-pixel means 256 colors. For a 24-bit

   color image, however, there is no color table.

4. Call the GetDIBits() function with the desired device context (DC), a

   pointer to the memory block as lpBitsInfo, and NULL as the lpBits

   parameter. Doing so instructs the device driver to fill in the

   biSizeImage field of the BITMAPINFOHEADER structure (this field

   should have been initialized to 0 in step 1). The biSizeImage field

   specifies the amount of memory required (in bytes) to store the

   bits that make up the image of the DIB. If this field remains 0

   after calling GetDIBits(), the application must calculate

   biSizeImage using the following formula:

      ((((biWidth * biBitCount) + 31) & ~31) >> 3) * biHeight

   This formula is required because each scan line of the image is

   aligned on a DWORD boundary.

5. Reallocate the memory block containing the BITMAPINFOHEADER and

   color table to provide additional memory to store the bits of the

   DIB.

6. Call GetDIBits() with the desired DC, a pointer to the memory block

   as lpBitsInfo, a pointer to the buffer for the bitmap bits as

   lpBits, and wUsage as DIB_RGB_COLORS. This stores the bits of the

   DIB with the BITMAPINFOHEADER structure and completes the color

   table.

In the sample applications listed above, the DibFromBitmap() function in

the DIB.C file of SHOWDIB, the BitmapToDIB() function in the DIBUTIL.C file

of WINCAP, and the BitmapToDIB() function in the DIB.C file of DIBVIEW

demonstrate the process above.

NOTE: The first two samples convert bitmaps into Windows 3.0 style DIBs and

do not support OS/2-style DIBs. DIBVIEW does support OS/2-style DIBs.

For more information on the Windows 3.0-style DIB format, see the

documentation for the BITMAPINFO, BITMAPINFOHEADER, and RGBQUAD structures

in the "Microsoft Windows Software Development Kit Reference Volume 2"

version 3.0 manual and in the Windows 3.1 SDK "Programmer's Reference,

Volume 3: Messages, Structures, and Macro's" manual.

To convert a DIB to a DDB, do the following:

1. Create a logical palette from the information in the DIB color

   table. Complete a LOGPALETTE data structure using the color values

   found in the color table, then call CreatePalette().

2. Select the logical palette into the desired device context using

   SelectObject(), then realize the palette using RealizePalette().

3. Call CreateDIBitmap() using the desired DC and the pointer to the DIB

   as the lpInfoHeader parameter. This function returns a handle to a

   DDB.

In the sample applications listed above, the BitmapFromDib() function in

the DIB.C file of SHOWDIB, the DIBToBitmap() function in the DIBUTIL.C file

of WINCAP, and the DIBToBitmap() function in the DIB.C file of DIBVIEW

demonstrate the process above.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiBmp


Discussion of Metafiles

Article ID: Q81497

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following is the text of the article "Metafiles". This article is

available in Windows Help file format in the Microsoft Software Library in

addition to the text presented below.

Download METAFILE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for METAFILE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735

      Download METAFILE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get METAFILE.EXE

                              Metafiles

                             by Ron Gery

ABSTRACT

--------

This article provides an overview of metafiles, their creation, and

their use. All metafile functions are discussed:

     CloseMetaFile

     CopyMetaFile

     CreateMetaFile

     DeleteMetaFile

     EnumMetaFile

     GetMetaFile

     GetMetaFileBits

     PlayMetaFile

     PlayMetaFileRecord

     SetMetaFileBits

PURPOSE AND DESIGN

------------------

A metafile is a mechanism for storing a graphics device interface

(GDI) "picture" -- a series of GDI functions that are used to draw an

image. A metafile consists of a series of records, each representing a

GDI function. When the metafile is played back, each stored function

is executed using its recorded parameters.

In effect, a metafile is a journal of GDI operations, and because all

GDI primitives can be recorded, any image that can be drawn can be

stored in a metafile. Because a metafile is in a standard format,

applications can exchange metafiles and use them for image storage.

The mapping mode of a metafile can be altered during playback. Thus,

the image can be scaled arbitrarily, with every component scaling

separately, which minimizes the loss of information for the image as a

whole and which is not characteristic of bitmaps. In addition, if the

image is sparse, a metafile uses less memory than does a bitmap of the

same image.

Because of their device independence and scaling abilities, metafiles

are useful for transferring images between applications, and most

applications support the Clipboard format associated with metafiles

(CF_METAFILEPICT). When treated as a single graphics primitive, a

metafile is easy to paste into an application without that application

needing to know about the specific content of the picture.

Basic USE

---------

Creating a metafile is as simple as calling the CreateMetaFile

function. An application can store a metafile in global memory or to

disk; using a memory metafile is faster, but it does use up memory.

The CreateMetaFile function returns a handle to a metafile device

context (DC). To record into a metafile any function that performs an

output operation or sets a drawing attribute, use this handle in place

of a normal DC handle when calling that function.

When the desired picture is stored in the metafile DC, the application

calls the CloseMetaFile function. As its name implies, the

CloseMetaFile function closes the metafile DC so that it can no longer

be used for recording. The function returns a handle to a metafile.

Now the metafile is ready for playback. The PlayMetaFile function is

the simplest way to play back a metafile. It accepts a destination DC,

which is where the image is to be drawn, and the metafile itself. In

this function, GDI recalls every stored instruction in the metafile

and executes it to the destination DC. The application can place the

image anywhere in the destination DC and scale it to the desired size

by altering the logical coordinate system (see below).

When the application is through with the metafile and before

terminating, the application must free GDI memory used by the metafile

by means of the DeleteMetaFile function. If the metafile is stored on

disk, the file remains untouched; only GDI memory associated with the

metafile is freed. GDI deletes all objects created during a metafile

playback as soon the playing is complete.

NEW CAPABILITIES FOR METAFILES IN WINDOWS VERSION 3.0 AND BEYOND

----------------------------------------------------------------

In Microsoft(R) Windows(TM) version 3.0, some major improvements

greatly increased the practicality of metafiles. The size restriction

on metafiles was essentially removed, and now their size is limited to

2^32 bytes of information (a DWORD value for the size). The size of

each record is no longer limited to 64K, so large bitmap operations

can now be handled successfully. This size increase would be useless,

however, if the number of objects were still limited by the size of

GDI's heap, so the META_DELETEOBJECT record was added to allow object

cleanup during playback.

For the object deletion to work correctly when recording to a

metafile, first deselect the object being deleted. Deleting an object

that is currently selected into a metafiling DC will work, but no

META_DELETEOBJECT record is created for that object. The "stranded"

object is deleted when the metafile playback is complete, but it

remains on the system throughout the playback.

Using device-independent bitmaps (DIBs) to store all bitmap

information significantly improves device independence. Using the new

DIB-based records, an application can place color bitmaps in metafiles

without losing information for functions such as BitBlt and

StretchBlt. The conversion to a DIB while recording, and from a DIB

during playback, is automatic.

The ability to use a metafile DC as the destination DC of a playback

is also new; a metafile can now be played into another metafile. Thus,

you can easily embed metafile information inside another metafile or

copy pieces of one metafile into another. A word of caution: Windows

version 3.0 crashes if you use PlayMetaFile and the destination DC is

a memory-based metafile. This situation is corrected in Windows

version 3.1, and you can use PlayMetaFileRecord for both memory-based

and disk-based metafiles in Windows versions 3.0 and 3.1.

LIMITATIONS

-----------

Some limitations in GDI APIs do not permit metafiles to be fully

functional. Because Windows version 3.0 lacked a scaling font

technology, fonts used in metafiles did not scale nicely as the

metafile was sized. The addition of TrueType(TM) in Windows version

3.1 eliminates this problem. Because no curve primitive is defined

beyond the basic Ellipse functionality, including a complex curve in a

metafile is not possible. Although you can use the Polygon function to

draw a curve, it will not scale smoothly. Regions do not scale at all,

rendering them virtually useless for any sort of complex clipping

within a metafile.

Under Windows version 3.0, when an application passes a handle to a

DC, determining whether the DC is real or a metafile is not possible.

Under Windows version 3.1, GetDeviceCaps(hDC, TECHNOLOGY) correctly

identifies a DC as a metafile DC (return value is DT_METAFILE) when

appropriate.

Unfortunately, Windows version 3.0 crashes or returns an incorrect

value when GetDeviceCaps is used with a metafile DC.

FINER POINTS OF OBJECT SCALING

------------------------------

A metafile that is created by an application and then passed to

another application is likely to be scaled. Scaling may alter the

desired image in a way not anticipated by the creating application

that does not scale the image. Every logical measure defined in a

logical object is scaled before the object is realized into physical

form.

For a logical object such as pens, the width is transformed from

logical to physical as an x-scalar value. If the metafile is scaled in

y but not in x, the pen width is unchanged. If the metafile is scaled

in x but not in y, the pen width does scale. Thus, using a pen of

width 1 in a metafile results in a pen that is wider (thick and slow)

when the metafile is scaled. If a nominal width pen (width of 1 at all

times) is desired, use 0 as the width because it is not affected by

mapping modes. A 0-width pen is drawn as having a width of 1.

Font sizing is more complicated. The two values that scale in a

logical font are the height and the width. Most applications use a

width of 0 to define a font, which results in a physical font with a

width that was designed for the given height. As the metafile is

stretched in x, the font remains the same size. As the metafile is

stretched in y, however, the physical font grows bigger and probably

wider. In and of itself, this is not a bad thing, but problems arise

when the metafile makes assumptions about the width of the font by

placing the characters of a text string individually by using

ExtTextOut with a width array or using a TextOut for each character.

In either case, the x-placement of each character scales with the

metafile, but the font's width does not necessarily scale accordingly,

which causes characters to overlap or be widely spaced.

The simplest way to overcome this situation is to not place the

characters individually but to use TextOut (or ExtTextOut with no

width array) to output the whole string. The text string remains

intact, but its size may change in relation to the rest of the image

when x and y are not scaled identically. Another possibility is to

define the font with a nonzero width so that it scales in x as well as

in y. Doing so in Windows version 3.0 is not wonderful because its

bitmapped fonts do not scale independently in x and y. Scaling a

font's width is possible with TrueType in Windows version 3.1.

Unfortunately, anytime a font's width is scaled, the look of the

typeface changes in ways not necessarily intended by the designers,

and a typographically "incorrect" typeface results.

PITFALLS TO AVOID WITH METAFILES

--------------------------------

GDI functions that return data either do not work properly or crash

the system if the DC passed in is a metafile DC. This category of

functions includes all Get functions as well as RectVisible,

PtVisible, EnumFonts, EnumObjects, DPtoLP, and LPtoDP. Any Escape

function that involves a data return is recorded in the metafile but

returns no meaningful data. A list of all functions that are supported

for metafiling is in the "Microsoft Windows Software Development Kit

Reference Volume 1," on page 2-42.

A number of functions in the Windows API appear to the naked eye to be

GDI functions with a DC parameter that should be able to be recorded

in a metafile; in reality these are functions of the window manager

interface and are not recorded in a metafile. They are DrawFocusRect,

DrawIcon, DrawText, ExcludeUpdateRgn, FillRect, FrameRect, GrayString,

InvertRect, ScrollDC, and TabbedTextOut. Because a metafile DC is not

actually associated with a device, you cannot use SetDIBits,

GetDIBits, and CreateDIBitmap with a metafile DC. You can use

SetDIBitsToDevice and StretchDIBits with a metafile DC as the

destination. CreateCompatibleDC, CreateCompatibleBitmap, and

CreateDiscardableBitmap are not meaningful with a metafile DC.

Calling SelectObject with a metafile DC does not return the previously

selected object in the metafile; it returns either 1 for a successful

recording or 0 for a failed recording. Attempting to use SelectObject

with a return of 1 to restore the previous object does not work and

causes a UAE in Windows version 3.0.

Support is limited for regions in metafiles. Regions do not scale

properly and should be avoided.

Metafiles that are created by an application and then passed to

another application should avoid altering the viewport extent in order

to be easily scalable (see below for a discussion of using mapping

modes with metafiles).

METAFILE INTERNALS

------------------

Metafiles have several layers of headers. GDI deals with the

METAHEADER structure, which sits directly before the bits. It is

described in the SDK reference, Volume 2, on page 9-7. The

METAFILEPICT structure is associated with a metafile when it is placed

in the Clipboard. Its basic function is to identify the mapping mode

and drawing size of the image, which are helpful for proper pasting

into another application.

Each metafile record consists of two parts, a descriptor and the

contents. Both are defined in the METARECORD structure:

   rdSize         The size of the record in WORDs. For many records, this

                  value is a constant because the number of parameters is

                  not variable. The size is a DWORD value that allows

                  records of more than 64K, a common occurrence with

                  bitmap manipulations.

   rdFunction     Identifies the function being recorded. It can be one

                  of the META_* values defined in WINDOWS.H. That list of

                  values also shows which GDI API functions can actually

                  be recorded in a metafile.

   rdParm[]       The space holder for the function's parameters. The

                  size of this array varies to fit as much memory as is

                  needed.

The SDK reference, Volume 2, for Windows version 3.0 describes the

ordering of parameters for all possible records, detailing those with

nonstandard parameters. This description is on pages 9-7 to 9-28.

Those GDI functions with a fixed number of parameters (that is, those

that have no arrays or strings) are recorded as they are called, with

the parameters stored in reverse order from the function definition.

The functions with complex parameters vary in the way they are stored.

One set of records does more than merely store parameters: the one

dealing with the creation, selection, and deletion of objects. Instead

of recording actual handles, which is not useful for playback, a

SelectObject function generates two records. The first is a creation

record (for example, META_CREATEPENINDIRECT). The second is

META_SELECTOBJECT, which has a parameter that is an index into the

object table. This object table is associated with the metafile and

grows as objects are added. Each new object gets a new entry in the

table and, hence, an index into the table. If an object is reselected

into a metafile, the corresponding META_SELECTOBJECT record references

the initial object table entry. When an application calls DeleteObject

for an object that was in the metafile, a META_DELETEOBJECT record is

added. It references the entry, and that entry is marked as open. The

next object that is created for the metafile reuses that entry and its

index. Object creation, selection, and deletion depend on proper

ordering during playback to achieve the proper results. For

PlayMetaFileRecord and the EnumMetaFile callback, this handle table

becomes a third component of the metafile. It is used invisibly when

PlayMetaFile is used.

Using Mapping Modes with Metafiles

----------------------------------

The METAFILEPICT structure contains information about the desired size

of the metafile. When an application pastes a metafile, it can use

this information to control the size of the metafile output. For this

to work cleanly between applications, be aware that:

 - The metafile is responsible for the window part of the mapping mode.

 - The player of the metafile is responsible for the viewport part of

   the mapping mode.

To perform a simple playback of the metafile, the application sets the

mapping mode to the mode specified in the METAFILEPICT structure, sets

the viewport origin to the desired placing of the metafile, and calls

PlayMetaFile. How big is this output image? Because the x-extent and

y-extent are given in logical units based on the specified mapping

mode, you can use LPtoDP to calculate the size of the image in pixels.

If the mapping mode is MM_ANISOTROPIC or MM_ISOTROPIC, sizing is not

quite so simple. Because the x-extent and y-extent of the image are

given in MM_HIMETRIC coordinates, first convert them to pixel values.

You can use LPtoDP after setting the mapping mode to MM_HIMETRIC or

use the HORZSIZE/HORZRES and VERTSIZE/VERTRES ratios (values obtained

using GetDeviceCaps) to convert manually. Before playback, the

application needs to set the viewport origin to the desired location,

set the mapping mode to the specified mode, and set the viewport

extents to the values calculated above. A properly created metafile

that uses MM_ANISOTROPIC or MM_ISOTROPIC mapping modes sets the window

extent at the start of the metafile to complete the mapping mode

equation. (The viewport itself is not sufficient; using any of the

other mapping modes sets appropriate values for the window extents.)

If no desired extents are provided in the METAFILEPICT structure, the

application doing the playback can arbitrarily choose a size.

Scaling a metafile that uses MM_ANISOTROPIC or MM_ISOTROPIC is easy --

merely change the viewport extents to the desired size before

playback. The viewport defines the size of the metafile image. To

scale metafiles that use any other mapping mode, first transform the

metafile to use MM_ANISOTROPIC. You don't need to change the metafile

itself, but you do need to change the mapping mode setup before

beginning the playback. Here is some simple code to do this:

   SetMapMode(hDC, lpMetaFilePict->mm);

   SetMapMode(hDC, MM_ANISOTROPIC);

The first call sets up the viewport and window for the desired mapping

mode. The second changes the mapping mode to be scalable but doesn't

change the viewport and the window information. Thus, the window

setting is in line with the mapping mode of the metafile and the

logical coordinates within while leaving the viewport ready for

scaling as desired.

MANIPULATION DURING PLAYBACK

----------------------------

You don't need to blindly play back metafiles. Windows has a mechanism

that allows an application to inspect every record before it is

played, change that record, or even invent a record of its own.

EnumMetaFile calls a callback routine with every record found in the

metafile. The application then calls PlayMetaFileRecord to play an

individual record. In the simplest case, the information passed to the

callback can be sent directly to PlayMetaFileRecord to simulate

PlayMetaFile. In more complicated scenarios, the application can

change the colors of objects or text of a TextOut, omit certain

records, or simply add new records to the playback.

NOTE: Altering the order of object creation, selection, or deletion

calls can adversely affect object management during playback. It is

important to keep in mind how the object table works when manipulating

object-based records.

Applications that want to store private information (for retrieval

during playback) in the metafile can do so by calling the Escape

function with MFCOMMENT. The function to be performed does nothing on

a regular DC but records that information in the metafile for a

metafile DC. Of course, EnumMetaFile must be used during playback for

the application to see and use it.

NOTE: If the metafile is placed in the Clipboard for transferring to

another application, the record is ignored during normal playback. To

ensure that two commenting applications do not become confused and

attempt to interpret the other's private data, place some kind of

signature (in the form of a few identifier bytes at the start) in the

comment.

METAFILE SUPPORT FUNCTIONS

--------------------------

The following functions concern metafile management:

   CopyMetaFile     Creates a metafile that is a copy of another

                    metafile.

   GetMetaFile      Retrieves a disk metafile, returning a handle to a

                    metafile.

   GetMetaFileBits  Returns a handle to a global memory block that

                    contains the actual metafile internals. The

                    application can then change, inspect or record the

                    data.

   SetMetaFileBits  Creates a memory metafile using the given metafile

                    data.

KNOWN PROBLEMS IN WINDOWS VERSION 3.0

-------------------------------------

The following list identifies problems with metafiles in Windows

version 3.0 that have been corrected in Windows version 3.1:

 - Attempting to record the ScaleWindowExt or ScaleViewportExt

   functions occasionally causes crashes in Windows 3.0

 - Recording StretchDIBits when using BITMAPCOREHEADER causes crashes

   in Windows 3.0. To avoid this problem, convert all DIBs to the

   BITMAPINFO format.

 - Using PlayMetaFile to play into a memory-based metafile causes

   crashes in Windows 3.0. Using disk-based metafiles or using

   PlayMetaFileRecord cause no problems.

 - Using EnumMetaFile and causing GDI's heap to get shuffled (by doing

   extensive object manipulation) sometimes results in a crash in

   Windows 3.0 when the enumeration is complete.

 - Passing a NULL hDC to EnumMetaFile causes invalid handle selections

   in Windows 3.0.

 - If an EnumMetaFile aborts, a global selector remains allocated

   in Windows 3.0.

 - An aborted EnumMetaFile does not give the return value of the last

   callback in Windows 3.0.

 - CopyMetaFile returns a nonzero value even if it fails a copy from

   a disk-based metafile to a memory-based metafile or vice versa.

   Memory-to-memory and disk-to-disk properly returns an error in

   Windows 3.0.

Copyright 1992 by Microsoft Corporation.  All rights reserved.

Additional reference words: 3.00 3.10 softlib METAFILE.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiMeta


DeviceCapabilities(DC_BINNAMES) Data Format

Article ID: Q82167

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

When an application calls the DeviceCapabilities() API with the nIndex

parameter set to DC_BINNAMES, 24 bytes are required for each bin name.

DeviceCapabilities() returns the name of each bin as a null-terminated

string in a character array. Each bin-name entry requires 24 bytes and

begins on the [(n-1) * 24] byte of the array.

The following code demonstrates how to allocate a block of memory, retrieve

the bin names, and walk through the array of bin names. The code assumes

that GetProcAddress() has been used to retrieve a long pointer to the

DeviceCapabilities() in the printer driver and that the pointer was stored

in the lpfnDevCap variable:

   if ((dwDMSize = (*lpfnDevCap)(lpszDevice, lpszPort, DC_BINNAMES,

                                 0L, lpDevMode))

        && (dwDMSize != (DWORD)(-1)))

   {

      if (hMem = GlobalAlloc(GMEM_MOVEABLE, (WORD)dwDMSize * 24))

      {

         lpMem = (LPINT)GlobalLock(hMem);

         nBins = (WORD)(*lpfnDevCap)(lpszDevice, lpszPort,

                                     DC_BINNAMES, lpMem, lpDevMode);

         for (lpBins = lpMem, i = 0; i < nBins; i++, lpBins += 24)

         {

            // lpBins points to the null-terminated bin name.

         }

         GlobalUnlock(hMem);

         GlobalFree(hMem);

      }

   }

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


PRB: "Orphan" Metafiles Not Tracked by Debugging Windows

Article ID: Q82168

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

If an application fails to delete a GDI object (for example, a pen)

before it shuts down, the debugging version of Windows will write a

warning message to the debug terminal. However, the debugging version

of Windows does not produce a warning message if an application

creates a metafile and does not delete it before termination.

This behavior does not unduly constrain memory because metafiles are

stored in global memory and are freed automatically at application

termination.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiMeta


CopyMetaFile() Creates Incorrectly Sized Destination

Article ID: Q82232

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

When an application calls CopyMetaFile() to create a copy of a metafile,

the size of the metafile is listed incorrectly in the destination metafile.

The destination size is three words larger than the source metafile.

MORE INFORMATION

================

The debugging version of Windows 3.1 contains code to validate the

size of a memory metafile. This code walks through every record in a

metafile and computes the total size. The code compares the computed

size with the size listed in the header. If the sizes do not match,

the debugging version of Windows displays the following message:

   Metafile has incorrect size

In most cases, this message indicates a corrupted or incorrectly

formed metafile. However, this message is also generated as a result

of copying an existing metafile due to the problem detailed above.

NOTE: By itself, the "metafile has incorrect size" message is harmless

and can be safely ignored. However, under certain circumstances, the

debugging version of Windows will also display the following message:

   Metafile is not terminated properly

This message indicates a more serious problem because, as the

validation code walked through the array of metafile records, it did

not locate a terminator record. An attempt to play an improperly

terminated metafile usually results in a General Protection Fault

(GP-Fault). To prevent this fault, GDI aborts the call to PlayMetaFile

and returns failure.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: GdiMeta


PRB: PrintDlg() Returns PDERR_NODEVICES w/ HP DeskJet

Article ID: Q83998

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In an application that uses the Print dialog box provided by the common

dialog boxes dynamic-link library (DLL), when the user selects HP DeskJet

Printers in the Specific Printer combo box, the value PDERR_NODEVICES

(0x1007) is returned to the application.

CAUSE

=====

The Hewlett-Packard (HP) DeskJet 500C printer driver was installed

incorrectly. The HP DeskJet driver provided with Windows 3.1 does

not support the HP DeskJet 500C.

RESOLUTION

==========

Reinstall the HP DeskJet 500C printer driver through the Control

Panel. When the Install Driver dialog box prompts for a vendor-

supplied printer driver disk, insert the driver disk provided with

the printer. For additional information on this procedure, query on

the following words in the Microsoft Knowledge Base:

   install and deskjet and 500c

MORE INFORMATION

================

PrintDlg() displays the Print dialog box. After the user selects a printer

and dismisses the dialog box, PrintDlg() sets the fields of a PRINTDLG data

structure to reflect the selections.

In the case described above, the hDevMode field points to a DEVMODE data

structure in which the dmDeviceName field is set to "HP DeskJet." However,

the printer name is listed in the [devices] section of the WIN.INI file as

"HP DeskJet Printers." Because the two entries do not match, PrintDlg

returns the PDERR_NODEVICES error to the application.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


PRB: GDI Functions Do Not Affect Printer Device Context

Article ID: Q84055

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When certain Windows Graphics Device Interface (GDI) functions are

used with a printer device context (DC), the functions do not

affect the printed results.

CAUSE

=====

The printer is a banding device and the application is not

performing banding.

RESOLUTION

==========

Modify the application to perform banding or remove any GDI

functions that are not supported by metafiles. The "Microsoft

Windows Software Development Kit Reference Volume 1" for version

3.0 lists on pages 2-41 and 2-42 the functions that are valid in a

metafile, and the "Microsoft Windows SDK: Programmer's Reference,

Volume 1: Overview," for version 3.1 lists the valid functions on

page 107; however, these lists contain some errors. To obtain an

updated list of valid functions, query on the following words in

the Microsoft Knowledge Base:

   prod(winsdk) and metafile and valid and functions

MORE INFORMATION

================

When an application prints to a banding device and does not perform

banding, Windows GDI collects all the output function calls and

creates a metafile. During the process of printing, GDI plays this

metafile into each of the bands received from the printer driver. Any

functions that are not supported in metafiles do not work under this

scenario.

For more information on adding banding to an application, query on the

following words in the Microsoft Knowledge Base:

   prod(winsdk) and banding and application

Other sources of information are Chapter 12 of the "Microsoft Windows

Software Development Kit Guide to Programming" for version 3.0 and

"Programming Windows" by Charles Petzold (Microsoft Press).

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


PRB: Loading Metafile Causes "Cannot Convert Picture" Error

Article ID: Q84926

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application attempts to load a metafile from disk, the following

error message is displayed in a message box:

   Cannot convert picture

CAUSE

=====

Some Windows applications expect to load a "placeable" metafile, which has

22 additional bytes, at the beginning of a normal metafile. Both metafile

types use the .WMF file extension; only the contents of the file change.

In an application, the GetMetaFile function does not read a placeable

metafile correctly; however, it returns a non-NULL value, which indicates

success.

RESOLUTION

==========

Load the metafile into an application that will accept both metafile types

and save the metafile in an appropriate type. The following applications

accept "placeable" metafiles: Aldus PageMaker, Microsoft PowerPoint,

Micrografx, Corel Draw, Microsoft Draw, Microsoft Graph, Microsoft Equation

Editor, and Microsoft Publisher.

For more information on placeable metafiles, query on the following words

in the Microsoft Knowledge Base:

   prod(winsdk) and placeable and metafile

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiMeta


Technical Details of TrueType Fonts in Software Library

Article ID: Q85202

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Microsoft Windows version 3.1 supports TrueType, a scalable font

technology developed by Apple Computer and adapted to Windows by

Microsoft.

Download TTF_SPEC.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TTF_SPEC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TTF_SPEC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TTF_SPEC.EXE

"The TrueType Font Files Specifications" is a 400-page book that

details the following:

 - How to construct a TrueType font from scratch (or build a font

   construction tool)

 - The TrueType programming language

 - The format of each subtable in the .TTF file and illustrations of

   table contents.

The TrueType specification is available in Microsoft Windows Help file

format. Windows 3.1 is required to view this document.

Additional reference words: 3.10 softlib TTF_SPEC.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiTt


PRB: Petzold's COLORS1 Sample Application Consumes Resources

Article ID: Q85285

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the COLORS1 sample application on pages 227-232 of the book

"Programming Windows 3" by Charles Petzold (Microsoft Press) is run

under Windows 3.1, the amount of free system resources available

after the program is complete is less than the amount available

before running the program.

CAUSE

=====

The program allocates system resources and does not free them.

RESOLUTION

==========

Make the following modifications to the WndProc function in the

COLORS1 sample:

1. In the code that processes the WM_VSCROLL message, find the

   following:

      DeleteObject (GetClassWord (hwnd, GCW_HBRBACKGROUND));

      SetClassWord (hwnd, GCW_HBRBACKGROUND,

           CreateSolidBrush (RGB (color[0], color[1], color[2])));

   Insert the following code in its place:

      DeleteObject (SetClassWord (hwnd, GCW_HBRBACKGROUND,

           CreateSolidBrush (RGB (color[0], color[1], color[2]))));

2. In the code that processes the WM_DESTROY message, find the

   following:

      DeleteObject (GetClassWord (hwnd, GCW_HBRBACKGROUND));

   Insert the following code in its place:

      DeleteObject (SetClassWord (hwnd, GCW_HBRBACKGROUND,

           GetStockObject (WHITE_BRUSH)));

MORE INFORMATION

================

In both cases above, the call to DeleteObject fails because the brush

is selected into a device context (DC). Each time the user moves one

of the scroll bars, the program creates a new brush from the GDI

module's heap space. Once the GDI heap reaches its limit of 64

kilobytes, none of the applications running in the system can create

GDI objects.

Under the debugging version of Windows 3.1, the following error

message is displayed on the debugging terminal each time the erroneous

code is executed:

   err COLORS1 GDI: GDI:Attempt to delete object owned by system

The resolution to this situation is to select a different brush into

the DC, and then to delete the old brush. Because the SetClassWord

function returns the previous value for the specified class word, it

is very straightforward to pass the return value from SetClassWord to

DeleteObject.

Additional reference words: 3.10

KBCategory: kbprg kbprb kbcode

KBSubcategory: GdiDc


PRB: IBM Proprinter Draft Mode Unavailable Under Windows 3.1

Article ID: Q86269

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the IBM Proprinter printer drivers included with Microsoft

Windows version 3.1, the Printer Setup dialog box does not provide

a draft mode option. Under Windows 3.0, the Proprinter printer

driver provides a choice between near letter quality (NLQ) and

draft mode.

CAUSE

=====

The Proprinter prints in draft mode by selecting a specific draft

mode font. Under Windows 3.1, the Proprinter driver was rewritten

using the Universal Printer Driver. The revised driver is

consistent with the printer's method of selecting fonts.

RESOLUTION

==========

To print in draft mode under Windows 3.1, format the text of your

document using the Fastfont printer font. This font provides draft

quality output and prints more rapidly than NLQ fonts. Text

formatted in other fonts prints in near letter quality.

Under Windows 3.0, the Proprinter driver selects the draft font

when the driver is configured for draft mode.

MORE INFORMATION

================

When the Proprinter driver is installed under Windows 3.1, use the

following five-step procedure to print a Windows Write document in

draft mode:

1. Start Windows Write and open the document.

2. Highlight the entire document.

3. Choose Fonts from the Character menu to bring up the Font dialog

   box.

4. Select the Fastfont font (each printer font has a printer symbol to

   the left of its name).

5. Print the document.

To make draft mode available when a Proprinter driver is installed, an

application must enumerate the fonts provided by the system. Because

Fastfont is a printer font, the enumeration must include printer

fonts. An application, such as Notepad, that does not provide a choice

of fonts limits the functionality available to its users.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


Windows TrueType Fonts Reading List

Article ID: Q88458

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article contains a list of documents available from Microsoft

that discuss TrueType fonts with reference to their use in Microsoft

Windows operating system version 3.1.

The documents are broadly classified into three categories on the

basis of their technical scope. Documents in the "End User" category

have information about using TrueType fonts for the Windows 3.1 end

user. Documents in the "Application Developer" category discuss the

impact of TrueType fonts on Windows-based applications and contain

technical details that let application developers use, and take advantage

of, TrueType font technology in their applications. Documents in the

"Font/Tool/Curious Developer" category contain information useful to

developers interested in developing their own TrueType fonts or

font-development tools, or interested in knowing about the inner

workings of the TrueType font technology.

Each entry contains information to help the reader obtain a copy of

the document. Many of the following documents will be available as

part of the upcoming Microsoft Developer Network (MSDN) CD. For more

information about this CD, call the Microsoft Developer Services Team

at (800) 227-4679.

MORE INFORMATION

================

End User Oriented Documents

---------------------------

Title: "Fonts in Windows 3.1"

What to expect: This document gives a comprehensive introduction to

the font technologies (including TrueType) used in Windows 3.1.

Finding a copy: This document is available as an application note

(WW0528); call Microsoft Product Support Services at (206) 637-7098 to

request this application note. It is also available in the

Software/Data Library (on CompuServe [GO MSL] and Microsoft OnLine) as

document S13367. Similar information can also be found in Chapter 9,

"Fonts," of the "Microsoft Windows Resource Kit" manual.

Title: "Microsoft TrueType Font Pack User's Guide"

What to expect: This document contains notes on installing and using

TrueType fonts, designing documents with TrueType fonts, and a brief

history of the TryeType font technology.

Finding a copy: This document is shipped with the Microsoft TrueType

Font Pack for Windows. The font pack is an assortment of 44 TrueType

fonts. Call Microsoft Consumer Sales at (800) 426-9400 for purchasing

information.

Application Developer Oriented Documents

----------------------------------------

Title: Chapter 18, "Fonts," in the "Guide to Programming"

What to expect: This document contains a gentle introduction to using

fonts in applications. It begins with a discussion of the fundamentals

of fonts, introduces the three font technologies used in Windows 3.1

(with an emphasis on TrueType fonts), discusses TrueType font

technology in the context of WYSIWYG and document/printer/platform

portability, and finally delves into the details of using fonts (with

due attention paid to TrueType) in Windows 3.1 applications.

Finding a copy: This manual is shipped with the Windows 3.1 Software

Development Kit (SDK). All the information is also available in the

SDK 3.1 online documentation (WIN31WH.HLP) under the subject headings

"Font Fundamentals," "Fonts in Windows," "TrueType Font Technology,"

and "Using Fonts in Applications."

Title: "Windows Font Mapping"

Author: Ron Gery

What to expect: This document discusses the Windows 3.1 font mapper

and how it controls the realization of fonts. Attention is paid to

selecting TrueType fonts and the effect of having TrueType fonts on

the fonts selected by applications developed for Windows 3.0 (which

does not have TrueType fonts).

Finding a copy: This document is available as part of the MSDN CD.

Title: "Using TrueType"

Author: Ron Gery

What to expect: This document gives a basic introduction to using

TrueType in an application under Windows 3.1. It discusses most of the

TrueType functions, enumerating and selecting TrueType fonts,

positioning TrueType characters in documents, and page layout.

Finding a copy: This document is available as part of the MSDN CD. It

is also available on CompuServe as file T2API.ZIP in LIB 8 of the

MSDNLIB forum.

Title: "TrueType and Microsoft Windows Version 3.1"

Authors: David Weise and Dennis Adler

What to expect: This document introduces some font concepts and

details the various aspects of using TrueType fonts in applications

developed for Windows 3.1.

Finding a copy: This document is available as part of the MSDN CD. It

is also available in the Software/Data Library (on CompuServe [GO MSL]

and Microsoft OnLine) as document S13451 and on CompuServe as file

TT.ZIP in LIB 8 of the MSDNLIB forum.

Font/Tool/Curious Developer Oriented Documents

----------------------------------------------

Title: "Advanced TrueType: GetGlyphOutline"

Author: Ron Gery

What to expect: This document presents an explanation of the

GetGlyphOutline function. It complements the definition of

GetGlyphOutline found in the Windows SDK 3.1 reference manual and

extends the definition by providing explanations for those portions of

the GetGlyphOutline function that were omitted in the SDK 3.1 manual.

Finding a copy: This document is available as part of the MSDN CD and

on CompuServe as file GLYPH.ZIP in LIB 1 (and eventually in LIB 9) of

the WINSDK forum.

Title: "An Introduction to Digital Typography Using TrueType"

Author: George Moore

What to expect: This transcript of a technical talk lists the basic

steps that a typical computer system goes through in order to display

characters on the output device and details these steps for TrueType

fonts in Windows 3.1.

Finding a copy: This document is available as part of the MSDN CD and

as in the Software/Data Library (CompuServe [GO MSL] and Microsoft

OnLine) document S13452.

Title: "Linear vs. Nonlinear Scaling"

Author: George Moore

What to expect: This transcript of a technical talk describes the

importance of being able to nonlinearly scale a font. It discusses how

a TrueType font vendor can use nonlinear scaling so that

low-resolution devices can display high-quality TrueType fonts.

Finding a copy: This document is available in the Software/Data

Library (CompuServe [GO MSL] and Microsoft OnLine) as document S13452.

Title: "TrueType Font Files Specification Version 1.0"

What to expect: This specification details how to construct a

TrueType font from scratch (or build a tool to do so), the TrueType

programming language, and the complete format of each subtable

contained in the .TTF file. It also contains illustrations.

Finding a copy: This document is spread over three documents (S13442,

S13443, S13444) and is available in the Software/Data Library

(CompuServe [GO MSL) and Microsoft OnLine). This specification is also

available on CompuServe as a Windows 3.1 Help file (TTHELP.ZIP) in LIB

1 (and eventually in LIB 9) of the WINSDK forum.

Additional reference words: 3.10 true type

KBCategory: kbprg

KBSubcategory: GdiTt


Causes for Failure of DC-Creation Functions

Article ID: Q89445

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The DC-creation functions [CreateDC(), CreateIC(), and

CreateCompatibleDC()] can fail for several reasons. When one of these

functions fails, it returns NULL. This article discusses eight causes

for DC-creation failure and provides a resolution or explanation for

each.

NOTE: Since the device driver would have already been loaded when

CreateCompatibleDC() is used, causes 1, 3, 5, 6, and 7 do not apply to

it.

Causes for Failure

------------------

 - Application runs out of file handles.

 - Insufficient system resources.

 - Insufficient global memory.

 - Global atom tables are full.

 - Not enough selectors are free.

 - The DEVMODE structure passed in is not the right size.

 - The logical device (device driver) or the physical device is not

   found.

 - The function cannot initialize the created DC.

MORE INFORMATION

================

The order in which the causes are listed below does not provide any

indication of how often each cause occurs.

Cause 1: Application Runs Out of File Handles

---------------------------------------------

Resolution 1: Use the SetHandleCount() function to open more file

handles. For more information on the file limit, query in the

Microsoft Knowledge Base on the following words:

   limits and open and files

Explanation 1: The GDI requires a file handle to load the device

driver and other files from disk.

Cause 2: Insufficient System Resources

--------------------------------------

Resolution 2: Verify that system resources are not lost because an

application does not delete objects that it creates. If you are

developing for Windows 3.1, use the debugging version of Windows 3.1.

For other information on tracking down lost system resources, query

in the Microsoft Knowledge Base on the following words:

   lost and heapwalk and system and resources

The article "Careful Windows Resource Allocation and Cleanup Improves

Application Hygiene," in the September 1991 issue of the "Microsoft

Systems Journal" discusses this issue further.

Explanation 2: These functions use the GDI's heap. Unless each

application frees all the resources that it allocates, eventually

Windows does not have enough memory to support the creation of DCs.

Cause 3: Insufficient Global Memory

-----------------------------------

Resolution 3: Close some applications and try again.

Explanation 3: The driver must be loaded into global memory.

Cause 4: Global Atom Tables Are Full

------------------------------------

Resolution 4: Minimize the creation of global atoms. Try closing some

applications.

Explanation 4: The GDI uses global atoms during the DC-creation

process.

Cause 5: Not Enough Selectors Are Free

--------------------------------------

Resolution 5: Minimize the use of GlobalAlloc(). Each GlobalAlloc()

call uses one of the limited selectors available to Windows (4096 in

protected mode and 8192 in 386 enhanced mode). For more information,

query in the Microsoft Knowledge Base on the following words:

   handle and limits and protected and enhanced mode

Cause 6: The DEVMODE Structure Passed In Is Not the Right Size

--------------------------------------------------------------

Resolution 6: The size of the DEVMODE structure varies from printer to

printer. You can find the size of the DEVMODE structure for a

particular printer by calling ExtDeviceMode() with wMode equal to

zero.

Cause 7: The Logical Device (Device

Driver) or the Physical Device Is Not Found

-------------------------------------------

Resolution 7: Check to see if you have the device driver and that the

physical device is connected and ready for use. You can check this

by attempting to print to that printer from other applications.

Cause 8: The Function Cannot Initialize the Created DC

------------------------------------------------------

Resolution 8: Restart Windows and try again.

Explanation 8: The objects used to initialize a DC are predefined.

This problem is likely to occur only when one of the applications in

the system has corrupted Windows' internal data.

Additional reference words: 3.00 3.10 fails

KBCategory: kbprg

KBSubcategory: GdiDc


PRB: Colors Lost Printing Color Metafile on Color Printer

Article ID: Q89571

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows graphical environment, when an application

prints a metafile that has a palette to a color printer, all colors

in the metafile are changed to black or white.

CAUSE

=====

The color printer does not support a palette.

RESOLUTION

==========

When the application creates the metafile, specify the colors using

the PALETTERGB macro instead of the PALETTEINDEX macro.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPal


Reasons for Failure of Bitmap Functions

Article ID: Q92529

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The bitmap functions (all) can fail for several reasons. Different

functions return different values to indicate failure. Read the

documentation for information about each function. This article combines

the causes of failure for all functions and provides a resolution or

explanation. A list of affected functions follows each cause. The causes

are:

 1. Invalid parameters.

 2. The device knows how to deal with a DIB (device-independent bitmap).

    Failure within that driver, as it works on the DIB, is propagated to

    GDI (graphics device interface).

 3. GDI is simulating the DIB operation. Bitmap is 64K or larger.

 4. A scan line (DWORD aligned) is 64K or larger.

 5. Insufficient global memory.

6. CBM_INIT is set in the dwInit field of CreateDIBitmap. GDI is setting

   the bits obtained from the DIB. The simulation fails if GDI cannot

   create a memory-based DC (device context) and select the bitmap into it.

 7. The source and destination DCs represent different physical devices.

 8. The source rectangle extends beyond the source bitmap.

 9. The point lies outside of the clipping region.

10. The bitmap dimensions were not set by SetBitmapDimension.

11. The bitmap resource could not be found (FindResource) or loaded

    (LoadResource) or locked (LockResource) in memory.

12. A memory DC was passed when a device DC was expected.

MORE INFORMATION

================

Cause 1: Invalid parameters.

Explanation 1: DCs, DIB headers, bitmap handles, starting scan line, and

other parameters should be valid.

Affected Functions: All functions.

Cause 2: The device knows how to deal with a DIB. Failure within that

driver, as it works on the DIB, is propagated to GDI.

Explanation 2: Low memory (within the device and/or global memory) and bugs

are the common sources of device driver failures. For more information,

search the Microsoft Knowledge Base or contact the device driver vendor.

Affected Functions: CreateDIBitmap, GetDIBits, SetBitmapBits, SetDIBits,

SetDIBitsToDevice, StretchDIBits.

Cause 3: GDI is simulating the DIB operation. Bitmap is 64K or larger.

Explanation 3: GDI's simulation of GetDIBits does not support bitmaps that

are 64K or larger.

Affected Functions: GetDIBits.

Cause 4: Each scan line (DWORD aligned) is 64K or larger.

Explanation 4: A scan line is one row of pixels in a bitmap.

Affected Functions: CreateBitmap, CreateCompatibleBitmap, CreateDIBitmap,

CreateDiscardableBitmap.

Cause 5: Insufficient global memory.

Explanation 5: GDI needs global memory to create bitmaps and to support

intermediate objects as it performs operations such as stretching, getting

bits from DIBs, and setting bits in DIBs.

Affected Functions: BitBlt, CreateBitmap, CreateBitmapIndirect,

CreateCompatibleBitmap, CreateDIBitmap, CreateDiscardableBitmap, GetDIBits,

LoadBitmap, SetDIBits, SetDiBitsToDevice, StretchBlt, StretchDIBits.

Cause 6: CBM_INIT is set in the dwInit field of CreateDIBitmap. GDI is

setting the bits obtained from the DIB. The simulation fails if GDI cannot

create a memory based DC and select the bitmap into it.

Affected Functions: CreateDIBitmap.

Cause 7: The source and destination DCs represent different physical

devices.

Explanation 7: The format for device-dependent bitmaps varies from one

device to another. Transferring bits directly between them is not allowed.

Affected Functions: BitBlt, PatBlt, StretchBlt.

Cause 8: The source rectangle extends beyond the source bitmap.

Explanation 8: These functions operate on a rectangular area in the bitmap

selected into the source DC. This rectangular area cannot extend beyond the

boundaries of the bitmap.

Affected Functions: BitBlt, StretchBlt.

Cause 9: The point lies outside of the clipping region.

Resolution 9: You may get another DC for the same window. The default

clipping region includes the entire visible client area.

Affected Functions: GetPixel, SetPixel.

Cause 10: The bitmap dimensions were not set by SetBitmapDimension.

Explanation 10: GetBitmapDimension retrieves the values set using

SetBitmapDimension.

Affected Functions: GetBitmapDimension.

Cause 11: The bitmap resource could not be found (FindResource) or loaded

(LoadResource) or locked (LockResource) in memory.

Resolution 11: Ensure that the bitmap resource exists and that the hInst

parameter refers to the correct hInstance. Try increasing the number of

file handles using SetHandleCount and increasing available global memory by

closing some applications. For more information about the causes of failure

of resource functions, query the Microsoft Knowledge Base on the following

keywords:

   prod(winsdk) and failure and LoadResource and FindResource and

   LockResource

Affected Functions: LoadBitmap, SetBitmapBits.

Cause 12: A memory DC was passed when a device DC was expected.

Explanation 12: SetDIBitsToDevice only works on device DCs.

Affected Functions: SetDIBitsToDevice.

Additional reference words: 3.00 3.10 fails SetBitmapDimensionEx

GetBitmapDimensionEx

KBCategory: kbprg

KBSubcategory: GdiBmp


PRB: How to Work Around WMFDCODE 64K Limitation

Article ID: Q94602

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

The sample application, WMFDCODE, supplied in the Windows 3.1 Software

Development Kit (SDK) can only read metafiles that are less than 64K in

size.

WORKAROUND

==========

To work around this 64K limitation, add one line and modify two lines. In

the file, WMFMETA.C, in the function RenderPlaceableMeta, add this line:

   long      lBytesRead;  // Number of bytes read.

Change the "_lread" function to "_hread" to allow the function to use HUGE

pointers to read the file. Also, change the return value to lBytesRead so

that it can accept a long value:

   /* read metafile bits */

   lBytesRead = _hread(fh, lpMem, (LONG)(mfHeader.mtSize * 2));

Next, change the if statement that compares the value returned from:

   if ( lBytesRead with -1 ) {

to the following line, which uses long values:

   /* if there was an error */

   if ( lBytesRead == -1L )  {

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiMeta


PRB: MULTIPAD Sample from Win 3.1 SDK Gives Printing Error

Article ID: Q94607

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The MULTIPAD sample that ships with the Microsoft Windows version 3.1

SDK allows only one print job to be sent to the printer. Any further

attempts to print result in the following error:

   Cannot print <document name>!

The document is not printed, and you must re-start MULTIPAD to do any

printing.

CAUSE

=====

The PRINTDLG data structure used for printing is a global variable, and

two members of this structure are invalid after the first print job is

sent. These members are not properly initialized for subsequent print

jobs.

RESOLUTION

==========

In the MPPRINT.C file, in the GetPrinterDC() routine, the following lines:

   if (pd.hDevNames)

     GlobalFree(pd.hDevNames);

   if (pd.hDevMode)

     GlobalFree(pd.hDevMode);

should be changed to:

   if (pd.hDevNames)

   {

       GlobalFree(pd.hDevNames);

       pd.hDevNames=NULL;

   }

   if (pd.hDevMode)

   {

       GlobalFree(pd.hDevMode);

       pd.hDevMode=NULL;

   }

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


Using GetCharABCWidths() to Calculate Text Extents

Article ID: Q94646

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Version 3.1 of the Microsoft Windows graphical environment introduces a set

of functions to manipulate TrueType fonts. An application can use the

GetCharABCWidths() function to accurately determine the advance width,

overhang, and underhang of a character. Because GetCharABCWidths() was

designed for use only with TrueType fonts, it is less useful when it

calculates the width of characters in a font in which the TrueType

rasterizer simulates the bold attribute. This article describes a method to

work around this limitation and also demonstrates a useful technique to

calculate the bounding rectangle for a string of text that provides

accurate results regardless of the font technology involved.

MORE INFORMATION

================

The TrueType rasterizer generates ABC character spacing to enable an

application to position characters exactly. The "A" spacing is the distance

added to the final position of the previous character (or to the beginning

of the line) before placing the glyph. The "B" spacing is the width of the

black part of the glyph. The "C" spacing is the distance to add to the

current position to account for the white space to the right of the glyph.

The total advance width for the glyph if given by A + B + C. Using the

advance width of one character, an application can determine where to

position the following character.

The GetCharABCWidths() function retrieves the widths, in logical units, of

consecutive characters in a specified range from the current TrueType font.

When the GetCharABCWidths() function returns a negative value for the "A"

or "C" width for a character, that character includes underhang or

overhang, respectively. The GetCharABCWidths function works only for

TrueType fonts.

An application can use the GetCharWidth() function to determine the advance

width of a character in any font. However, because GetCharWidth() has no

mechanism to provide a negative "A" or "C" width, it cannot be used to

place text exactly.

Under Windows 3.1, if the TrueType rasterizer simulates the bold attribute,

the information returned by the GetCharABCWidths() function is less

accurate. (For example, the standard fonts provided with Windows 3.1

include the WingDings font in standard weight only. If an application

requests a bold version of WingDings, the TrueType rasterizer simulates the

bold attribute by manipulating the original, normal-weight font.) When an

application uses the GetCharABCWidths() function to determine the advance

width of a manipulated TrueType font, the difference between the returned

ABC width and the true ABC width is one for each character.

To work around this limitation, the application can add one to the ABC

width of each character. However, to use this method, the application must

determine that the rasterizer has simulated the bold attribute. The

following function demonstrates determining that a TrueType font has bold

enabled. Select a TrueType font into the display context (DC) before

calling this function.

NOTE: If you are not using the MM_TEXT mapping mode, you will need to

convert the value one from device coordinates to logical coordinates before

adding the value to the character width.

  #include "windows.h"

  #include "windowsx.h"

  BOOL NEAR PASCAL IsBoldSimulated( HDC hDC )

  {

     TEXTMETRIC                 tm ;

     OUTLINETEXTMETRIC          otm ;

     GetTextMetrics( hDC, &tm ) ;

     if (tm.tmWeight <= FW_NORMAL)

        return FALSE ;

     otm.otmSize = sizeof( OUTLINETEXTMETRIC ) ;

     /* Call GOTM() with the pointer to the buffer.  It will

      * fill in the buffer.

      */

     if (!GetOutlineTextMetrics( hDC, otm.otmSize, &otm ))

        return FALSE ;  // Probably not a TrueType font

     /* See the documentation on OUTLINETEXTMETRIC for a

      * description of the otmfsSelection member.

      */

     if (!(otm.otmfsSelection & 0x0020)) // bit 5 means bold

           return TRUE ;

  } /* IsBoldSimulated()  */

Note that this limitation occurs only in Windows 3.1 (the GDI.EXE file

dated March 10, 1992). Any application that uses the methods described in

this article to work around this limitation must version-bind its code.

The following function demonstrates how to use the GetCharABCWidths()

function to determine the bounding rectangle for a string of text. Although

this function is very similar to the GetTextExtent() and

GetTextExtentPoint() functions in Windows, it correctly accounts for

overhang and underhang caused by negative "A" and "C" widths. This function

also demonstrates how to version-bind the code that works around the

limitation in Windows 3.1.

  /****************************************************************

   *  UINT WINAPI GetTextExtentABCPoint( HDC hDC, LPSTR lpsz,

   *                                     int cb, LPSIZE lpSize )

   *

   *    Just like GetTextExtentPoint() but only works on TT fonts

   *    and uses GetCharABCWidths().

   *

   *    Unlike GetTextExtent() and GetTextExtentPoint() which

   *    return a BOOL, this function returns the absolute value

   *    for the "A" value of the first character if it is

   *    negative otherwise it returns 0.

   *

   ****************************************************************/

  UINT WINAPI GetTextExtentABCPoint( HDC hDC, LPSTR lpsz,

                                     int cb, LPSIZE lpSize )

  {

     int          A, C ;

     UINT         nRet = 0 ;

     static LPABC lpABC ;

     GetTextExtentPoint( hDC, lpsz, cb, lpSize );

     if (lpABC ||

     (lpABC = (LPABC)GlobalAllocPtr( GHND, 256*sizeof(ABC) )))

     {

        if (GetCharABCWidths( hDC, 0, 255, lpABC ))

        {

           int         n ;

           /* We now have an array of ABC structures

            */

           for ( lpSize->cx = 0, n = 0 ; n < cb ; n++ )

           {

              lpSize->cx += (

                             lpABC[(int)lpsz[n]].abcA +

                             lpABC[(int)lpsz[n]].abcB +

                             lpABC[(int)lpsz[n]].abcC ) ;

           }

           if( cb )

           {

              A = lpABC[(int)lpsz[0]].abcA;

              if( A < 0 )

              {

                 nRet = -A ;

                 lpSize->cx -= A;

              }

              C = lpABC[(int)lpsz[cb-1]].abcC ;

              if ( C < 0 )

                 lpSize->cx -= C ;    // two minus' make a plus

           }

           /* Bug in Windows 3.1.  If the tt font is embolded then

            * add one to the width for each char.

            */

           if ((BOOL)LOWORD( GetVersion() ) == 0x0A03 &&

               IsBoldSimulated( hDC ))

              lpSize->cx += cb ;

        }

        else

           GetTextExtentPoint( hDC, lpsz, cb, lpSize ) ;

        return nRet  ;

     }

     return nRet ;

  } /* GetTextExtentABCPoint()  */

Additional reference words: 3.10 GetCharABCWidths GetTextExtent TrueType

KBCategory: kbprg

KBSubcategory: GdiFnt


Managing Icons Extracted Using ExtractIcon()

Article ID: Q95392

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The ExtractIcon() API is new to Windows version 3.1. The Window 3.1

Software Development Kit (SDK) "Programmer's Reference, Volume 2:

Functions" description of this function, on page 296, does not address

management of the memory occupied by the icons extracted using

ExtractIcon. This article provides that information.

MORE INFORMATION

================

When an application calls ExtractIcon(), it passes an hInstance. When

that hInstance is terminated, the memory occupied by that icon is

automatically freed.

Applications that extract several icons during their lifetime may not

be able to keep several unused icons in memory. Such applications can

call DestroyIcon to free memory occupied by icons.

If application A needs to pass a handle to an icon to application B in

the system, it should make a copy of the icon with CopyIcon() using the

hInstance of application B. This ensures that even if application A

quits while application B is still using the icon, the handle to the

icon passed to application B will still be valid.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: GdiCurico


Utilizing High Color Resolution Devices

Article ID: Q97342

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

BIGBIT is a technical note in the Microsoft Software Library that discusses

the use of devices with high color resolution (more than 8 bit). It

provides information useful both application and device driver writers.

BIGBIT is a Windows Help file.

Download BIGBIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S14157.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BIGBIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BIGBIT.EXE

Additional reference words: 3.10 softlib BIGBIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiMisc


PRB: Metafiles and Palettes

Article ID: Q98268

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The metafile list inside of GDI's heap grows by a WORD.

CAUSE

=====

This happens each time an application selects a palette into a metafile

device context (DC).

RESOLUTION

==========

If a palette is never deleted, then this block is never freed and keeps on

growing until GDI's heap fills and the system crashes.

This problem is heightened by the fact that the application typically

selects the default stock palette back in so the application can free its

custom palette. Because an application cannot delete the default stock

palette, this memory is never freed inside of GDI's heap.

MORE INFORMATION

================

Below is the code necessary to correct the problem. There are no rules

regarding when to call FlushGDIHeap(); however, Microsoft recommends

doing this after a major operation, such as after saving a file or

printing. Determining whether you need to flush the GDI heap depends

on how often your application selects in a palette in a metafile.

Optionally, you could periodically call TOOLHELP and see if the GDI

resources are greater than X%.

Sample Code

-----------

SEG       segGDI, segNil;

HANDLE    hPalSys;

int       iPal;

BOOL      fEnableFlushHeap;

/* ---------------------------------------------

   The following code is used to initialize the

   FlushGDIHeap function.

   --------------------------------------------- */

API VOID InitOLE(VOID)

{

  HANDLE hGDISegment;

  /* Called once during application initialization.  Sets up the

     state for FlushGDIHeap.  */

  /* Make sure this version of Windows has the bug. */

  if (wWinVer >= 0x400)

          return;

  /* This is from MSDN and it gets GDI's DS.

   * The module handle return by LoadLibrary is actually the module's DS.

   */

  hGDISegment = LoadLibrary("GDI.EXE");

  if (hGDISegment <= HINSTANCE_ERROR)

          return;

  FreeLibrary(hGDISegment);

  Glob(segGDI) = HIWORD(GlobalLock(hGDISegment));

  if (Glob(segGDI) != segNil)

  {

    GlobalUnlock(hGDISegment);

    Glob(hPalSys) = GetStockObject(DEFAULT_PALETTE);

    // Debug version of Windows has palette metafile list

    // heap handle in different offset than in retail Windows

    // versions greater than 3.0.

    // The offset is in WORD's.

    Glob(iPal) = (GetSystemMetrics(SM_DEBUG) != 0 &&

            FGTWinVer30()) ? 11 : 9;

    Glob(fEnableFlushHeap) = TRUE;

  }

} // end InitOLE

/*=========================================================================

=

FlushGDIHeap

===========================================================================

=*/

STATIC VOID NEAR FlushGDIHeap(VOID)

{

  HANDLE hPal;

  SEG segTmp;

  WORD *pPal, *pw, w2, iPal;

  /* If the flush heap operation is not enabled then return. */

  if (!Glob(fEnableFlushHeap))

          return;

  /* Switch to GDI's heap for Local memory functions. */

  segTmp = Glob(segGDI);

  hPal = Glob(hPalSys);

  /* Offset in Pal data structure to second metafile list handle.

  * This varies between debug and retail (see InitOLE).

  */

  iPal = Glob(iPal);

  _asm {

          push ds

          mov  ds,segTmp

       }

  /* Shrink the metafile list table down for the system palette. */

  if ((pPal = (WORD *)LocalLock(hPal)) != NULL)

  {

     /* First free memory from the standard object metafile list.

      * All GDI objects have this list associated with them if

      * they are selected into metafiles.

      */

     if (pPal[4] != hNil)

     {

        if ((pw = (WORD *)LocalLock(pPal[4])) != NULL)

        {

           w2 = *pw;

           LocalUnlock(pPal[4]);

           LocalReAlloc(pPal[4], (w2+1) * sizeof(WORD), LHND);

        }

     }

     /* Second, free memory from the secondary metafile list.

      * Only palettes have this list.

      */

     if (pPal[iPal] != hNil)

     {

       if ((pw = (WORD *)LocalLock(pPal[iPal])) != NULL)

       {

          w2 = *pw;

          LocalUnlock(pPal[iPal]);

          LocalReAlloc(pPal[iPal], (w2+1) * sizeof(WORD), LHND);

       }

     }

     LocalUnlock(hPal);

  }

  /* Restore application's data segment. */

  _asm {

         pop ds

       }

} // end FlushGDIHeap

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb kbcode

KBSubcategory: GdiMeta


Increasing the Transmission Retry Timeout for Printing

Article ID: Q99801

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The number of seconds for transmission retry timeout can be set

through the Connect dialog box in the Printers application of the

Control Panel. The entry in the Transmission Retry field is limited to

999 and is set individually for each printer. This limit cannot be

increased. However, an application can increase the default

transmission retry value up to 65536 by editing the

TransmissionRetryTimeout value in the Windows section of WIN.INI. This

setting takes effect when the Print Manager is disabled.

MORE INFORMATION

================

The TransmissionRetryTimeout entry in the Windows section of WIN.INI

is the default retry value. It is limited to 65536 and resembles the

following:

   [windows]

   TransmissionRetryTimeout=45

There is also a retry value for each printer in the PrinterPorts

section of WIN.INI; it is limited to 999 and resembles the following

(the format is "device=driver,port,DeviceTimeout,RetryTimeout"):

   [PrinterPorts]

   HP LaserJet IIISi=HPPCL5MS,FILE:,15,45

   HP LaserJet IIISi PostScript=pscript,FILE:,15,90

When the retry value for a particular printer is changed via the

Control Panel, the value in the PrinterPorts section is changed. The

Control Panel does not alter the value in the Windows section. The

TransmissionRetryTimeout value in the Windows section must be changed

manually by editing WIN.INI with a text editor or programmatically by

calling a function such as WriteProfileString(). GetProfileInt() can

be used to determine the current setting.

NOTE: Control Panel sets the default transmission retry value for the

PostScript driver (PSCRIPT.DRV) to twice the default value of other

drivers.

The TransmissionRetryTimeout setting is used only if Print Manager is

disabled. Otherwise, the RetryTimeout value listed in the PrinterPorts

section for the current printer is used.

For more information about disabling Print Manager programmatically,

query on the following words in the Microsoft Knowledge Base:

   print and manager and disable

Additional reference words: 3.10 USR_Sys_OtherCP

KBCategory: kbprg

KBSubcategory: GdiPrn


Enabling and Disabling Print Manager

Article ID: Q99802

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

An application can programmatically enable and disable the Print

Manager by altering the setting of the "spooler=" field in the Windows

section of WIN.INI; the setting will be "spooler=yes" if Print Manager

is enabled and "spooler=no" if Print Manager is disabled. The

GetProfileString() function can be used to determine the current

setting; WriteProfileString() can be used to change the current

setting. The WM_WININICHANGE message should be sent to all top-level

windows if changes are made to WIN.INI.

This method only works before an application starts printing. Once the

printer driver calls the OpenJob() function, GDI either will or will

not execute the spooler depending on the "spooler=" setting.

An application can monitor the number of jobs in the Print Manager

queue by processing the WM_SPOOLERSTATUS message. This could be useful

to ensure there are no print jobs in the queue before disabling Print

Manager. The WM_SPOOLERSTATUS message is sent to all top-level windows

from Print Manager whenever a job is added to or removed from the

Print Manager queue. The number of jobs remaining is in

LOWORD(lParam).

NOTE: WM_SPOOLERSTATUS is for informational purposes only.

Please see the documentation for GetProfileString(),

WriteProfileString(), WM_WININICHANGE, and WM_SPOOLERSTATUS for more

information about them.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Diagnosing Printing Problems in Your Application

Article ID: Q101413

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

--------------------------------------------------------------------

SUMMARY

=======

When you are in the midst of development and concentrating on coding,

it is easy to loose sight of problem areas external to your

application. When diagnosing a printing problem in your application,

there are three major areas to be aware of:

 - Environment/network issues

 - Printer and printer driver issues

 - Application coding issues

You should rule out a problem in the first two areas before making any

coding changes.

MORE INFORMATION

================

Environment/Network Issues

--------------------------

Check List:

1. Do other applications print correctly?

2. Try a clean boot.

3. Can you print to a local printer?

4. Try different Print Setup and Print Manager settings.

5. Ensure that there's enough disk space in the TEMP directory.

Do other Windows-based applications such as Paintbrush or Microsoft Write

print successfully? If they do not, then the problem probably isn't

with your application. You should try a clean boot (starting your

computer after all unnecessary commands have been removed from your

CONFIG.SYS and AUTOEXEC.BAT files) to help narrow down the problem.

Try printing to a local printer to ensure that the problem isn't

related to your network. If your application prints correctly to a

local printer and not to the network printer, the problem could be

with incorrect network settings.

Is Print Manager enabled? If not, try enabling Print Manager. Try

turning off the Fast Printing Direct To Port option if it's on. For

more information about how these settings affect printing in Windows,

please see the following articles in the Microsoft Knowledge Base:

   ARTICLE-ID: Q82746

   TITLE     : General Information About Print Manager and Windows 3.1

   ARTICLE-ID: Q82747

   TITLE     : How Windows Prints to a Network

Make sure there's enough disk space for the temp files that are

created during printing. If the TEMP environment variable points to a

network drive, make sure it has the correct permissions set on it.

Printer and Driver Issues

-------------------------

Check List:

1. Test with various printer drivers.

2. Check the Windows Drivers Library (WDL) for an updated printer driver.

3. Test with different display drivers.

4. Check for incorrect printer and Print Manager settings.

5. Reinstall the printer driver.

It is important to test with several different printers to determine

whether the problem happens only on a specific printer. If so, be sure

to check the WDL to determine whether there's an updated driver for

the printer.

Be sure to test printing on machines with different display drivers.

Printer drivers normally do not support all output functions and rely

on GDI to assist. In many cases, GDI in turn calls into the display

driver to do the actual work. So, a bug in the display driver could

show up during printing. For example, test with the standard VGA

driver that shipped with Windows 3.1 and another display driver with

more capabilities such as the 8514/a.

Check for incorrect settings on the printer. Make sure the printer is

set up correctly in Print Manager. Check that the correct properties,

printer port, and so on, have been specified. It's possible the

printer driver file is corrupt. Try removing the printer driver

through Control Panel, deleting the printer driver file (along with

deleting UNIDRIV.DLL if appropriate) and reinstalling the driver

through Control Panel.

Application Coding Issues

-------------------------

Check List:

1. Compare your code to PRNTFILE and/or DIBVIEW.

2. Implement banding in your application.

3. Check all return codes to narrow down the problem.

4. Set up HDC after each NEWFRAME, EndPage, or NEXTBAND.

5. Make sure each EndPage() has a matching StartPage().

6. Use QUERYESCSUPPORT.

7. If printing bitmaps, use device-independent bitmaps (DIBs).

Do the Windows Software Development Kit (SDK) sample programs PRNTFILE

and DIBVIEW print correctly on your system? If so, comparing your code

to these samples will be useful. Note that there is a minor bug in

PRNTFILE. To fix it, move to where the bAbort flag in PRNTFILE.C is

initialized to right after the IDM_PRINT case, before any calls to

escape. Without this fix, with some printers, if you begin printing,

cancel, and try to print again, you will receive an error on the

STARTDOC escape. This is because some printer drivers call your

application's abort procedure during STARTDOC, and the bAbort flag has

not been reinitialized after canceling the previous print job.

Do you do banding (using the NEXTBAND and BANDINFO escapes) in your

application? This is particularly important if you are doing a lot of

graphics output or you are making calls to the SDK region functions.

There have been problem reports concerning the region functions

consuming GDI resources in nonbanding applications, and at this time

the only known resolution is to implement banding in your application.

If you don't do banding in your application then Windows does it for

you by creating a disk-based metafile and then playing back the entire

metafile into each printer band. Using the NEXTBAND escape eliminates

the disk-based metafile so the printing process is greatly simplified.

As an added benefit, you should notice an increase in performance.

After adding the NEXTBAND escape, try optimizing your code even more

using the BANDINFO escape.

The sample program DIBVIEW demonstrates the correct usage of both the

NEXTBAND and BANDINFO escapes. If you need more information on

banding, query on the following word in the Microsoft Knowledge Base:

   GdiPrnBanding

The Microsoft Developer Network (MSDN) CD article "Printing" is a must

read for anyone implementing printing under Windows. Keep in mind that

the article was written around the time Windows 3.1 was released when

the problems with the Windows banding/metafile code were not known.

Because of this, the article does not emphasize the importance of

implementing banding in your application. For CompuServe customers,

"Printing" can be downloaded from the file 10-33.ZIP in library

section number 10 of the MSDNLIB forum.

If you are just learning about printing under Windows, or if you are

considering implementing banding in your application, the Printing

Self-Study Module has a great deal of information and sample code

ready for your use. For more information about the Printing Self-Study

Module, see the following application note in the Microsoft Knowledge

Base:

   Appnote: PW0778: Printing Self-Study Module

Here's a few other ideas:

 - The escapes NEXTBAND and NEWFRAME and the EndPage function reset the

   printer HDC to default values. If you've made any changes to the

   printer HDC such as selecting in GDI objects (fonts, pens, brushes,

   and so forth) or changing the mapping mode, then you must set up the

   printer HDC again. The symptom here is that the first page prints fine

   and subsequent pages do not.

 - Make sure each call to EndPage() has a matching StartPage(). EndPage()

   fails (return -1) if StartPage() has not been called.

 - Have you set an Abort procedure and is it properly exported? The

   Windows 3.0 PostScript driver version 3.3 causes an unrecoverable

   application error (UAE) if there isn't an Abort procedure. With

   all the hundreds of Windows printer drivers available, it is best

   to avoid unnecessary complications and just set a simple Abort

   procedure.

 - If you're trying to mix the PASSTHROUGH escape with calls to GDI

   functions then you must do banding and use the PASSTHROUGH escape

   on the first band only.

 - Use QUERYESCSUPPORT before calling printer escapes to make sure that

   the printer driver supports the escape you want to call next.

 - If you are printing bitmaps, always use DIBs (device independent

   bitmaps). Use the sample program WINCAP or DIBVIEW as a model for

   printing DIBs. Query the Microsoft Knowledge Base for more information

   about these samples.

Additional reference words: 3.10 appnote

KBCategory: kbprg kbappnote

KBSubcategory: GdiPrn


Reading and Writing Icons from ExtractIcon

Article ID: Q104570

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

This article is specifically about device dependent icons. The

ExtractIcon() function does not save the contents of the icon to a

file. The programmer needs to implement this in his or her application.

Below are code samples that allow you to read and write the data to a file

so that DrawIcon() can be used.

MORE INFORMATION

================

The following is a summary of the steps needed to save the hIcon to a file:

1. Get the desired handle to the icon by using ExtractIcon().

2. Find the size of the global memory by using GlobalSize().

3. Lock the handle of the icon using GlobalLock().

4. Open a new file by using OpenFile().

5. Write the contents out to the file by using _lwrite().

6. Close the file.

// -----------------------------------------------

//   Parameters: hIcon - passed in

//   Returns:    TRUE on success, FALSE on failure

// -----------------------------------------------

int NEAR _pascal SaveMyIcon( HICON hIcon)

{

  int       fh, i, iResult;

  UINT      uiSize;

  DWORD     dwSize;

  OFSTRUCT  of;

    if (!hIcon)

      return FALSE;

    dwSize  = GlobalSize(hIcon);

    lpGMem  = GlobalLock(hIcon);

    fh = OpenFile ("myicon.bin", &of, OF_WRITE | OF_CREATE);

    if (fh == -1)  // If NOT opened successfully.

    {

     MessageBox(NULL, "Unable to create file", NULL, MB_OK );

     return FALSE;

    }

    uiSize = _lwrite(fh, (LPSTR)lpGMem, (UINT)dwSize);

    _lclose(fh);

    if (uiSize == -1 || uiSize < (UINT)dwSize)

    {

       MessageBox(NULL, "Unable to read file", NULL, MB_OK );

       return FALSE;

    }

    else // Everything worked, return hGMem.

    {

      return (HICON)hGMem;

    }

}

The following is a summary of the steps needed to read the hIcon from

a file:

1. Open the file with OpenFile.

2. Get the size of the file with _fstat.

3. Make a chunk of memory, hMem, for the file by using GlobalAlloc.

4. Lock the memory by using GlobalLock.

5. Read the file into memory by using _lread.

6. Close the file by using _lclose.

7. Unlock the memory by using GlobalUnlock.

8. Pass the hMem to DrawIcon.

// --------------------------------------

// Read in the binary icon data from disk

// --------------------------------------

HICON NEAR _pascal LoadMyIcon()

{

  int       iResult, fh;

  UINT      nBytesRead;

  struct    _stat   buf;

  OFSTRUCT  ofFileInfo;

  nBytesRead = 0;

  if ( OpenFile((LPSTR)"myicon.bin",(LPOFSTRUCT)&ofFileInfo,OF_EXIST) != -1

)

  {

    // Open the file. Its existence has already been checked.

    fh = _lopen("myicon.bin", OF_READ);

    if (fh == -1)  // if NOT opened successfully

      return FALSE;

    // File the file structure to get the file size.

    iResult = _fstat(fh, &buf);

    if ( !iResult)

    {

      hGMem = GlobalAlloc(GHND, (DWORD)buf.st_size);

      if (0==hGMem)

      {

        _lclose(fh);

        return(FALSE);

      }

      // Lock the memory.

      if (!(lpGMem = GlobalLock(hGMem)))

      {

        GlobalFree(hGMem);

        _lclose(fh);

        return(FALSE);

      }

      // Seek to the beginning of the file.

      _llseek(fh, 0, 0);

      nBytesRead = _lread(fh, (LPSTR)lpGMem, buf.st_size );

    }

    _lclose(fh);

    if (nBytesRead == -1 || nBytesRead < buf.st_size)

    {

      MessageBox(NULL, "Unable to read file", NULL, MB_OK );

      return FALSE;

    }

    else // Everything worked, return hGMem.

    {

      return (HICON)hGMem;

    }

  }

  else

  {

    MessageBox( NULL, "File not found", NULL, MB_OK );

    return FALSE;

  }

}

WARNING: This will work correctly until the user changes his or her

display-driver type to a different resolution, or from mono to color,

or from color to mono.

Additional reference words: 3.10

KBCategory: kbprg kbcode

KBSubcategory: GdiCurico


Nesting Scalable Metafiles

Article ID: Q107171

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

The ability to use a metafile device context (DC) as the destination

DC of a metafile playback is new in Windows 3.1. A metafile can now be

played into another metafile, and therefore you can easily place one

metafile inside another metafile or copy pieces of one metafile into

another.

It is sometimes common for an application to create a metafile that

will be passed to another application. In this case, it is likely that

the metafile will be scaled. Scalable metafiles can easily be created

by using the MM_ANISOTROPIC mapping mode, the SetWindowExt() function,

and the SetViewportExt() function. The logical extent of a scalable

metafile is defined by the parameters in the SetWindowExt() function.

It can be complicated when playing one scalable metafile into another

scalable metafile device context. The logical extents of the two

metafiles may be different and the desired location of the metafile

being played may be offset from the origin of the destination metafile

DC. The OffsetWindowOrg() and ScaleViewportExt() functions can be used

to alter the metafile DC's attributes in order to play the source

metafile correctly into the destination metafile DC. The

SaveDC/RestoreDC commands can be used to preserve the metafile DC's

attributes while playing the source metafile into it.

MORE INFORMATION

================

When creating a scalable metafile, you are responsible for setting the

logical extent of the metafile by calling SetWindowExt(). When playing

back a scalable metafile, the application can set the mapping mode to

MM_ANISOTROPIC and call SetViewportExt() to specify the desired size

of the metafile. When playing a scalable metafile into another

scalable metafile, the ratio of the logical extents must be used to

determine how far to offset the window origin, so the metafile will be

played in the correct location. Also, the viewport must be scaled

accordingly so the metafile being played in the destination metafile

DC will be the correct size. Calling SaveDC() before playing the

metafile and RestoreDC() after playing the metafile will preserve the

attributes of the destination metafile DC.

The following code can be used to play a scalable metafile into

another scalable metafile DC. Both the logical extents of the source

and destination are needed. The first parameter is the destination

metafile DC. The second parameter specifies the metafile that will be

played into the destination metafile DC. The next four parameters

specify a logical rectangle where the metafile will be played on the

destination metafile DC. The two parameters after that specify the

logical extents of the destination metafile DC, and the last two

parameters are the logical extents of the metafile being played.

Sample Code

-----------

void PlayInMetafile(HDC hdcMeta,HMETAFILE hmf,int nLeftRect,

                    int nTopRect,int nRightRect,int nBottomRect,

                    int xLogExt, int yLogExt, int xHmfLogExt,

                    int yHmfLogExt)

{

    SaveDC(hdcMeta);

    OffsetWindowOrg(hdcMeta,-MulDiv(nLeftRect, xHmfLogExt,

                    nRightRect-nLeftRect), -MulDiv(nTopRect,

                    yHmfLogExt, nBottomRect-nTopRect));

    ScaleViewportExt(hdcMeta,nRightRect-nLeftRect,xLogExt,

                             nBottomRect-nTopRect,yLogExt);

    PlayMetaFile(hdcMeta,hmf);

    RestoreDC(hdcMeta,-1);

}

Additional reference words: 3.10 view port

KBCategory: kbprg

KBSubcategory: GdiMeta


Getting/Setting the Default Printer from Windows

Article ID: Q110663

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SUMMARY

=======

The "device=" entry in the [windows] section of WIN.INI refers to the

default printer. The way to change it is to call

WriteProfileString("windows", "device", szNewPrinterSpec), where

szNewPrinterSpec is of the form "printer name, printer driver base

filename, port connected to printer". For example:

   HP LaserJet IIISi,HPPCL5MS,LPT1:

MORE INFORMATION

================

The currently installed printers are contained in the WIN.INI [devices]

section. It is possible to build a list of the installed printers by

calling GetProfileString("devices", NULL, "", szDriverNames,

sizeof(szDriverNames)). This will fill the szDriverNames with the names of

all printers installed separated by a null byte, with a double null byte at

the end of the list.

Choose the new printer from the list provided and call

GetProfileString("devices", szDriverRequested, "", szPrinter,

sizeof(szPrinter)) with szDriverRequested set to the printer name

requested. Once the call returns, the szPrinter will contain the rest of

the information needed to create the szNewPrinterSpec. Create a new

szPrinterSpec from both szPrinterRequested and szPrinter and make the call.

Once WIN.INI is updated, call SendMessage(HWND_BROADCAST, WM_WININICHANGE,

0, 0L) to send the correct notification to all top level windows after

WIN.INI gets changed programmatically. Applications that care about WIN.INI

listen for this message and reread WIN.INI as needed.

The following code gets and sets the default printer:

   #include <windows.h>

   #include <string.h>

   #define MAXSTRING 255

   int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,

                      LPSTR lpszCmdLine, int CmdShow)

   {

      char szFmtStr  [] = "%s,%s";

      char szDevice  [] = "device";

      char szDevices [] = "devices";

      char szWindows [] = "windows";

      char szDefault [] = "default";

      char szInstPrn [] = "Set this installed printer as default?";

      char szDefPrn  [] = "The default printer";

      char szBuff    [MAXSTRING];

      char szRetBuff [MAXSTRING];

      char szVal     [MAXSTRING];

      int nBytes;

      HLOCAL hLocal;

      PSTR pszBuf, pszKey;

      nBytes = GetProfileString(szWindows, szDevice, szDefault, szRetBuff,

                                sizeof(szRetBuff));

      MessageBox(NULL,szRetBuff, szDefPrn, MB_OK | MB_ICONINFORMATION);

      hLocal = LocalAlloc(LHND, 1024);

      pszBuf = (PSTR) LocalLock(hLocal);

      GetProfileString(szDevices, NULL, szDefault, pszBuf, 1024);

      for (pszKey = pszBuf; *pszKey != '\0'; pszKey += strlen(pszKey) + 1)

      {

         int nID;

         GetProfileString(szDevices, pszKey, szDefault,

                          szVal, sizeof(szVal));

         wsprintf(szBuff, szFmtStr, (LPSTR) pszKey, (LPSTR) szVal);

         nID = MessageBox(NULL, szBuff, szInstPrn, MB_YESNOCANCEL

                         | MB_ICONQUESTION);

         switch(nID)

         {

            case IDNO:

               continue;

            case IDYES:

               WriteProfileString(szWindows, szDevice, szBuff);

               WriteProfileString(NULL, NULL, NULL);

               SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0L);

            default:

               break;

         }

         break;

      }

      LocalUnlock(hLocal);

      LocalFree(hLocal);

      return(0);

   }

Additional reference words: devices 3.00 3.10 3.50

KBCategory: kbprg

KBSubcategory: GdiPrn


An Alternative to SpoolFile()

Article ID: Q111010

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

Applications written for Windows 3.1 can use either the SpoolFile()

function or the PASSTHROUGH printer escape to send a printer-specific file

to Print Manager for spooling to a printer. Because there are several

caveats to using SpoolFile(), using the PASSTHROUGH printer escape is often

a better choice.

MORE INFORMATION

================

The following is a list of known limitations of the Windows SDK SpoolFile()

function:

 - SpoolFile() is documented as being for use with local printers only.

   Using SpoolFile() with network printers results in undefined behavior;

   sometimes you may get output, sometimes you may get a general protection

   (GP) fault.

 - Print Manager must be enabled to use SpoolFile().

 - Print Manager treats the file exactly as it treats temporary files

   generated through "normal" GDI printing. This has two major

   implications:

   - The file must use the correct language/format for the printer.  Print

     Manager does not attempt to interpret or modify the file in any way,

     but simply writes the contents to the port.

   - Print Manager deletes the file when done spooling it to the port.

 - Finally, a bug in SpoolFile() causes Print Manager to cause a GP fault

   when the application that called SpoolFile() terminates before Print

   Manager is done spooling the file to the port.

The following demonstrates how to use the PASSTHROUGH escape:

/* FILE: spool.c */

#include <windows.h>

#include <print.h>

#include <commdlg.h>

#include <string.h>

// Function prototypes

BOOL FAR PASCAL PrintFile(LPSTR, HDC, HGLOBAL, HGLOBAL);

VOID SendFile(HDC, LPSTR);

HDC  GetPrinterDC(HGLOBAL, HGLOBAL);

BOOL CALLBACK __export PrintAbortProc(HDC, int);

// Play with this number

#define BUFSIZE 2048

// Convenient structure for use with PASSTHROUGH escape

typedef struct

{

  WORD wSize;

  BYTE bData[2];                  // placeholder

} PASSTHROUGHSTRUCT, FAR *LPPTS;

BOOL bAbort;        // Global printing abort flag

//*************************************************************

//

//  PrintFile()

//

//  Purpose:

//          Reads a file and copies it to a printer using the

//          PASSTHROUGH escape.

//

//  Parameters:

//      LPSTR   szFile    - Pointer to path/filename to print

//      HDC     hPrnDC    - Handle to printer DC or NULL

//      HGLOBAL hDevNames - Handle to DEVNAMES struct or NULL

//      HGLOBAL hDevMode  - Handle to DEVMODE struct or NULL

//

//  Return:

//      Returns nonzero for success or zero for failure.

//

//  Comments:

//      hDevNames and hDevMode are only used if hPrnDC is NULL.

//      If both hPrnDC and hDevNames are NULL, the default

//      printer is used.

//

//  History:    Date       Author     Comment

//              6/03/93    JMS        Created

//

//*************************************************************

BOOL FAR PASCAL PrintFile ( LPSTR   szFile,

                            HDC     hPrnDC,

                            HGLOBAL hDevNames,

                            HGLOBAL hDevMode )

{

  int iEsc;

  BOOL bLocalDC = TRUE; // Assume we must create a DC (hPrnDC == NULL)

  bAbort = FALSE;       // Haven't aborted yet

  // Make sure we have a printer DC

  if (!hPrnDC)

    hPrnDC = GetPrinterDC(hDevNames, hDevMode);

  else

    bLocalDC = FALSE;   // Use passed in hPrnDC

  if (!hPrnDC)

    return FALSE;

  // PASSTHROUGH is required. If driver doesn't support it, bail out.

  iEsc = PASSTHROUGH;

  if (!Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL))

    {

    bAbort = TRUE;

    goto MSFCleanUp;

    }

  // If we created the DC, install an abort procedure. We don't have

  // a Cancel dialog box, but the abort proc enables multitasking.

  // (Use __export and compile with -GA or -GD so we don't need

  // a MakeProcInstance.)

  if (bLocalDC)

    Escape (hPrnDC, SETABORTPROC, 0, (LPSTR) PrintAbortProc, NULL);

  // Call EPSPRINTING if it is supported (that is, if we're on a

  // PostScript printer) to suppress downloading the pscript header.

  iEsc = EPSPRINTING;

  if (Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL))

    {

    iEsc = 1;  // 1 == enable PASSTHROUGH (disable pscript header)

    Escape(hPrnDC, EPSPRINTING, sizeof(int), (LPSTR)&iEsc, NULL);

    }

  SendFile(hPrnDC, szFile); // Send file to printer (could do multiple

                            // files)

MSFCleanUp:                 // Done

  if (bLocalDC)             // Only delete DC if we created it

    DeleteDC(hPrnDC);

  return !bAbort;

} /* PrintFile() */

VOID SendFile(HDC hPrnDC, LPSTR szFile)

{

  static LPPTS lpPTS=NULL;          // Pointer to PASSTHROUGHSTRUCT

  OFSTRUCT ofs;

  HFILE hFile;

  hFile = OpenFile((LPSTR) szFile, &ofs, OF_READ);

  if (hFile == HFILE_ERROR)

    {

    bAbort = TRUE;  // Can't open file!

    return;

    }

  if (!lpPTS &&

       !(lpPTS = (LPPTS)GlobalLock(GlobalAlloc(GPTR, sizeof(WORD) +

 BUFSIZE))))

    {

    bAbort = TRUE;  // Can't allocate memory for buffer!

    return;

    }

  Escape (hPrnDC, STARTDOC, 0, "", NULL);

  // Loop through the file, reading a chunk at a time and passing

  // it to the printer. QueryAbort calls the abort procedure, which

  // processes messages so we don't tie up the whole system.

  // We could skip the QueryAbort, in which case we wouldn't need

  // to set an abort proc at all.

  do {

    if ((lpPTS->wSize=_lread(hFile, lpPTS->bData, BUFSIZE)) == HFILE_ERROR)

      {

      bAbort = TRUE;  // error reading file

      break;

      }

    Escape(hPrnDC, PASSTHROUGH, NULL, (LPSTR)lpPTS, NULL);

    }

  while ((lpPTS->wSize == BUFSIZE) && QueryAbort(hPrnDC, 0));

  if (!bAbort)

    Escape(hPrnDC, ENDDOC, NULL, NULL, NULL);

  _lclose(hFile);

} /* SendFile() */

HDC GetPrinterDC(HGLOBAL hDevNames, HGLOBAL hDevMode)

{

  HDC hdc;

  char szPrinter[64];

  LPSTR szDevice=NULL, szDriver=NULL, szOutput=NULL;

  LPDEVMODE lpdm;

  if (hDevNames)

    {

    LPDEVNAMES lpdn = (LPDEVNAMES) GlobalLock(hDevNames);

    szDriver = (LPSTR) lpdn + lpdn->wDriverOffset;

    szDevice = (LPSTR) lpdn + lpdn->wDeviceOffset;

    szOutput = (LPSTR) lpdn + lpdn->wOutputOffset;

    if (hDevMode)

      lpdm = (LPDEVMODE) GlobalLock(hDevMode);

    }

  else

    {                       // Get default printer info

    GetProfileString ("windows", "device", "", szPrinter, 64);

    if (!((szDevice = strtok (szPrinter, "," )) &&

          (szDriver = strtok (NULL,      ", ")) &&

          (szOutput = strtok (NULL,      ", "))))

            return NULL;    // No default printer

    lpdm = NULL;  // Don't use DEVMODE with default printer

    }

  hdc = CreateDC(szDriver, szDevice, szOutput, lpdm);

  if (hDevMode && lpdm)

    GlobalUnlock(hDevMode);

  if (hDevNames)

    GlobalUnlock(hDevNames);

  return hdc;

} /* GetPrinterDC() */

BOOL CALLBACK __export PrintAbortProc(HDC hdc, int code)

{

  MSG msg;

  while (!bAbort && PeekMessage(&msg, 0, 0, 0, PM_REMOVE))

    {

    TranslateMessage(&msg);

    DispatchMessage(&msg);

    }

  return (!bAbort);

}  /* PrintAbortProc() */

/*** EOF: spool.c ***/

The PrintFile() function in the above sample code can be used instead of

SpoolFile(). PrintFile() uses the PASSTHROUGH printer escape to send a file

to the printer. This method has several advantages over SpoolFile():

 - It works equally well with local and network printers.

 - It works whether or not Print Manager is enabled.

 - It does not delete the file when done, but could be easily modified to

   do so if desired.

 - It avoids the GP fault problem mentioned above.

 - It can be easily modified to print several files in a row to a single

   printer with a single call to PrintFile().

The primary disadvantages of PrintFile() are that it's slower than giving

Print Manager the file directly, and it requires the printer driver to

support the PASSTHROUGH escape. Almost all drivers support PASSTHROUGH,

with the current LaserJet 4 driver (HPPCL5E.DRV) being a notable exception.

For printer drivers that do not support the PASSTHROUGH escape,

applications can use the driver RAW.DRV, which is available in the

Microsoft Software Library.

For more information about the driver RAW.DRV, please see the following

article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q35708

   TITLE     : Using a Device Driver to Send Binary Data to a Printer

There have been reports of problems using the PASSTHROUGH escape with the

driver HPPCL5A.DRV. This is the version of the printer driver for the HP

LaserJet III series that shipped with Windows 3.1. A more recent version of

the driver (HPPCL5MS.DRV), which has no known problems with the PASSTHROUGH

escape, is available in the Windows Driver Library (WDL). To obtain the

latest driver for the HP LaserJet III series, download the self-extracting

file HPPCL5.EXE from the WDL.

For more information on the WDL, including its location and a list of all

available drivers, please see the following article(s) in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q95611

   TITLE     : Windows Driver Library Information Files

Intermixing the PASSTHROUGH escape with calls to GDI output functions can

be problematic. It is best to print using either the PASSTHROUGH approach

or using the "normal" Windows printing method using GDI output functions.

If you must intermix the two approaches, you will get best results if you

use the NEXTBAND escape and send the raw data via the PASSTHROUGH escape on

each first (all text) band and call the GDI output functions on subsequent

printer bands.

NOTE: The Win32 API provides APIs for spooling raw print jobs.

Additional reference words: 3.10 RAW gpf gp-fault

KBCategory: kbprg

KBSubcategory: GdiPrn


How GDI Sends Data to the Printer

Article ID: Q112387

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Develpment Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

If the "Fast Printing Direct to Port" option is enabled from the Microsoft

Windows Control Panel, print-job data will be sent directly to the printer

port, using COMM.DRV. Otherwise, MS-DOS _lwrite() calls will be used to

write data to the port. The Fast Printing Direct to Port setting

corresponds to the DosPrint entry in the [Windows] section of WIN.INI.

MORE INFORMATION

================

When a print job is started by a printer driver, the printer driver will

call into GDI, using the OpenJob() function. Within OpenJob(), GDI

uses the following sequence of steps to determine whether to print directly

to the port, or to use MS-DOS _lwrite:

1. Attempts to call the network driver's WNetOpenJob() function,  if that

   function exists. If WNetOpenJob succeeds, indicating  that the port is a

   redirected network port, GDI will use  _lwrite() to write to the port,

   regardless of the "Fast Printing  Direct to Port" setting. Otherwise:

2. Checks to see if "Fast Printing Direct to Port" is selected. If it is

   not selected, GDI will use _lwrite() to write to the port. Otherwise:

3. Calls OpenComm() for the selected port. If OpenComm() succeeds, the

   communications API, which call into COMM.DRV, will be used to write to

   the port [WriteComm()]. Otherwise:

4. Uses _lwrite().

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: GdiPrn


Calculating MM_HIMETRIC Units for the METAFILEPICT

Article ID: Q113254

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

To copy a Windows metafile to the clipboard, it is necessary to allocate

memory for a METAFILEPICT structure and fill it out appropriately. This

article shows one approach to filling out the METAFILEPICT struct when you

want to provide a suggested size for playing back the metafile in addition

to having it be scalable.

MORE INFORMATION

================

The first step in copying the metafile to the clipboard is to allocate

global memory for the METAFILEPICT struct. After copying this structure to

the clipboard, the memory that you allocated for the METAFILEPICT is owned

by the clipboard and you should not lock it or modify it.

The METAFILEPICT struct is defined as follows:

typedef struct tagMETAFILEPICT

{

   int     mm;

   int     xExt;

   int     yExt;

   HMETAFILE hMF;

} METAFILEPICT;

The field mm in the METAFILEPICT specifies the mapping mode in which the

metafile is to be played. In order for your metafile to be scalable, you

should specify MM_ANISOTROPIC as the mapping mode for the mm field. The

members xExt and yExt specify the width and height of the rectangle within

which the metafile is played.

When the mapping mode is MM_ANISOTROPIC, the values for xExt and yExt

should be in MM_HIMETRIC units. Of course you can always calculate the

values yourself, but it's very easy to use the functions LPtoDP and DPtoLP

to let Windows do the calculation for you. The LPtoDP function converts

logical points to device points; DPtoLP converts device points to logical

points.

You need a handle to a device context (hDC) compatible with the display in

order to do the conversion. There are many ways to obtain a display hDC.

The functions GetDC(NULL), CreateCompatibleDC(NULL), CreateDC("DISPLAY",

NULL, NULL, NULL), GetDC(hWnd), and GetWindowDC(hWnd) all return a suitable

display hDC.

If you call any of the above functions to obtain an hDC, unless you

explicitly change the mapping mode, it is in the default mapping mode,

MM_TEXT. In the MM_TEXT mapping mode, one logical unit equals one device

unit.

If you used the MM_TEXT mapping mode to create your metafile, then it is

quite likely that you will also know the width and height of your metafile

in device units (pixels). In this case, to calculate values for xExt and

yExt, just temporarily set the mapping mode to MM_HIMETRIC and call the

function DPtoLP to convert the device units to MM_HIMETRIC units. For

example:

pt.x = nWidth;

pt.y = nHeight;

SaveDC(hDC);

SetMapMode(hDC, MM_HIMETRIC);

DPtoLP(hDC, &pt, 1);

RestoreDC(hDC, -1);

Because the y-axis is inverted in the MM_HIMETRIC mapping mode, DPtoLP will

return negative values for the y coordinate, and therefore you should

specify yExt as a positive value. One way to do this is to use the C run-

time library function abs to get the absolute value of pt.y.

If the mapping mode in which you created your metafile is something other

than MM_TEXT, then you probably will know the width and height of the

metafile in logical units. In this case, to calculate values for xExt and

yExt you must first convert the width and height from logical units to

device units before converting to MM_HIMETRIC units. To do this, the hDC

that you use for the calculation must be in the same mapping mode that was

used to create the metafile. If you created the metafile in the

MM_ANISOTROPIC or MM_ISOTROPIC mapping mode, you must also set the window

and viewport extents appropriately so that the scaling factor is correct in

the call to LPtoDP.

pt.x = nWidth;

pt.y = nHeight;

// assumes the hDC is in the appropriate mapping mode

LPtoDP(hDC, &pt, 1);

SaveDC(hDC);

SetMapMode(hDC, MM_HIMETRIC);

DPtoLP(hDC, &pt, 1);

RestoreDC(hDC, -1);

The hMF field in the METAFILEPICT structure should contain the handle to a

Windows memory metafile. Because the memory allocated for any object that

is placed on the clipboard is owned by the clipboard, this handle should be

a copy of the metafile that you created. To fill in the hMF member, call

the function CopyMetaFile.

The following function demonstrates the above approach of filling out the

METAFILEPICT struct, and then copies the metafile to the clipboard:

//*************************************************************

//

//  CreateClipboardMetaFile()

//

//  Purpose:  Allocates and fills out a METAFILEPICT struct and

//                  copies the metafile to the clipboard.

//

//

//  Parameters:

//

//  HWND    hWnd     For OpenClipboard().

//  HDC     hDC      For LPtoDP & DPtoLP. The mapping mode

//                   must match the logical units that

//                   nWidth and nHeight are specified in.

//  int     nWidth   Width of the metafile in logical units.

//  int     nHeight  Height of the metafile in logical units.

//

//

//  Return: (void)

//

//*************************************************************

void CreateClipboardMetaFile(HWND hWnd,

                             HDC hDC,

                             HANDLE hMF,

                             int nWidth,

                             int nHeight)

{

   HANDLE         hMem;

   LPMETAFILEPICT lpMFP;

   POINT          pt;

   // Allocate memory for the METAFILEPICT struct

   hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(METAFILEPICT));

   lpMFP = (LPMETAFILEPICT)GlobalLock(hMem);

   // MM_ANISOTROPIC ensures that it is scalable on playback

   lpMFP->mm = MM_ANISOTROPIC;

   // Convert the object width and height into MM_HIMETRIC units.

   pt.x = nWidth;

   pt.y = nHeight;

   // First get the width and height into device units.

   // This assumes that the hDC is in the mapping mode that

   // matches the logical units that nWidth and nHeight are

   // specified in. If nWidth and nHeight are already in device

   // units, then this step isn't necessary.

   LPtoDP(hDC, &pt, 1);

   // Temporarily set the mapping mode to MM_HIMETRIC

   SaveDC(hDC);

   SetMapMode(hDC, MM_HIMETRIC);

   DPtoLP(hDC, &pt, 1);

   RestoreDC(hDC, -1);

   // Because the y-axis is inverted in the MM_HIMETRIC mapping mode,

   // DPtoLP returns negative values for the y coordinate.

   // Because of this, we should specify yExt as a positive value.

   // Also guard against the obscure case that the logical units

   // that nWidth was specified in would cause pt.x to be negative.

   lpMFP->xExt = abs(pt.x);

   lpMFP->yExt = abs(pt.y);

   // Fill in the handle to the metafile.

   // Make a copy of the metafile because the memory block allocated

   // for it will be owned by the clipboard. The memory allocated for the

   // METAFILEPICT struct will also be owned by the clipboard.

   lpMFP->hMF = CopyMetaFile(hMF, NULL);

   GlobalUnlock(hMem);

   // Copy the metafile to the clipboard.

   OpenClipboard(hWnd);

   EmptyClipboard();

   SetClipboardData(CF_METAFILEPICT, hMem);

   CloseClipboard();

}

Additional reference words: 3.10 metafile MM_HIMETRIC METAFILEPICT

KBCategory: kbprg

KBSubcategory: GdiMeta


PRB: dmPrintQuality Does Not Affect Text Print Quality

Article ID: Q114601

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

An application is able to change printer settings such as paper

orientation without requiring user intervention, but the same method does

not work to change the print quality of text from letter quality (LQ) or

near letter quality (NLQ) to draft. The ExtDeviceMode() function is used to

attempt this change through the dmPrintQuality member of the DEVMODE

structure.

Please see the MORE INFORMATION section below for details about how the

dmPrintQuality member of the DEVMODE structure, the DRAFTMODE printer

escape, and the selection in the Print Quality combobox in the Print

Options dialog, affect the "draft" mode or "quality" of printed output.

CAUSE

=====

This is a limitation of the standard DEVMODE structure. There is no

programmable way to change the text print quality (from LQ/NLQ to draft or

vice versa) without user intervention because it is not in the standard

DEVMODE structure.

With printer drivers that offer a Letter Quality/Draft option, such as

most Unidrv-based dot-matrix printer drivers, the user can change the

text print quality from the Printers applet in Control Panel as follows:

1. select the printer

2. choose Setup

3. choose Options

4. choose Letter Quality or Draft from the Print Quality combo box

An application can allow the user to change this in the same manner by

using the DM_PROMPT (or DM_IN_PROMPT) flag for the fwMode parameter of

ExtDeviceMode(). This will bring up the Print Setup dialog box and the

user can then choose Options and then select the desired print quality.

An exception to this is the IBM Proprinter Unidrv-based printer drivers.

The Proprinters are dot-matrix printers but they do not provide a print

quality choice through the Print Options dialog. Please see the following

article in the Microsoft Knowledge Base for information about selecting a

draft font with a Proprinter driver:

   ARTICLE-ID: Q86269

   TITLE     : PRB: IBM Proprinter Draft Mode Unavailable Under Windows 3.1

Please see the following article in the Microsoft Knowledge Base for

information about the proper use of the ExtDeviceMode() function:

   ARTICLE-ID: Q112641

   TITLE     : SAMPLE: Using ExtDeviceMode() to Modify Printer Settings

STATUS

======

This feature is under consideration for a future release of Microsoft

Windows.

MORE INFORMATION

================

There are three types of "draft" settings that affect the appearance or

"quality" of printed output. They are not clearly explained in the SDK

documentation:

dmPrintQuality

--------------

dmPrintQuality controls the graphics resolution only. If the application

sets draft mode by setting the dmPrintQuality member of the DEVMODE

structure to DMRES_DRAFT, it means the driver should print graphics in the

lowest possible resolution for that device. For example, a laser printer

that offers the choice of 300, 150, or 75 dpi resolution will be set to 75

dpi. A dot-matrix printer that supports 240x144, 120x144, and 120x72 dpi

will be set to 120x72 dpi. Text is not affected by this setting, unless the

text is printed as graphics.

DRAFTMODE

---------

If the application sets draft mode by calling the DRAFTMODE printer escape,

it means the driver should print text only. It will not print graphics.

Print Quality

-------------

If the user selects Draft from the Print Quality list in the Print Options

dialog as discussed in this article, then the driver will tell the printer

to print text in draft mode. Graphics are not affected by this setting.

Additional reference words: 3.00 3.10 docerr Epson Okidata Deskjet NEC

Pinwriter fail fails DM_PRINTQUALITY DM_YRESOLUTION

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


PRB: GDI Heap Fills Up While Playing a Metafile

Article ID: Q119453

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

During the playback of a metafile or printing, the GDI heap fills up and it

is not possible to create additional GDI objects.

CAUSE

=====

This filling of the GDI heap can be caused by a metafile that does not

contain any DELETEOBJECT metafile records. The GDI objects created during

the metafile playback never get deleted, which fills up the GDI heap. An

application that prints without using banding in Windows version 3.1 causes

a metafile to be created on behalf of the application. The problem listed

above then occurs.

The DELETEOBJECT metafile record is a new feature developed for Windows

version 3.1. This record is used to record DeleteObject() calls into the

metafile, so that the specified GDI object is deleted during playback of

the metafile. If you call DeleteObject() on an object that is currently

selected into a metafile device context (DC), a DELETEOBJECT record will

not be recorded into the metafile. The documentation for DeleteObject()

states that the object must not be selected into a DC.

RESOLUTION

==========

Make sure to deselect the object in your metafile DC before calling

DeleteObject() to delete the object. For more information on calling

DeleteObject() for a metafile object, please see the following article in

the Microsoft Knowledge Base:

   ARTICLE-ID: Q68296

   TITLE     : Windows 3.x Metafiles Support DeleteObject()

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: GdiMeta


PRB: Creating Many Fonts Causes a GPF in Windows 3.1

Article ID: Q119454

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When you create or generate TrueType fonts, selectors are lost. Eventually,

if you create enough fonts, this problem causes a general protection fault

(GPF) in your application.

CAUSE

=====

Under Windows version 3.1, each time a new TrueType font is created, the

cache is allocated to hold the TrueType font data. This memory is allocated

as discardable memory, so that Windows can discard the font data and give

the memory to other applications that need more memory. This way, TrueType

font caching does not adversely affect available memory.

The cache memory blocks are not discarded unless forced. Deleting the font

handle (HFONT) does not cause the TrueType font cache memory to be deleted.

This is a system optimization made in case another application uses the

same font.

Each cached TrueType font uses two selectors for its font data. Windows has

a system-wide limit of 8192 selectors. When you create many TrueType fonts

at once, you can run out of free selectors, which causes Windows to behave

unexpectedly; your application may have a general protection fault (GPF).

Deleting the font handles when you are finished with the fonts does not

prevent this behavior.

In addition, if you allocate a single TrueType font and change the mapping

mode frequently, a new physical font is generated for each mapping-mode

change. This can also cause the system to run out of free selectors and

your application to have a GPF.

RESOLUTION

==========

GlobalAlloc() a large block of memory, create a font, and then delete the

font. This forces segments to be discarded, so that the selectors are

freed.

The True Type font cache in Windows 95 is designed so that this problem

does not occur.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubCategory: GdiFnt


How to Print a Single Line Without Formfeed

Article ID: Q124649

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.10

---------------------------------------------------------------------

SUMMARY

=======

This article shows by example how to have an application print one line at

a time without a formfeed. Windows does not inherently provide this ability

because it is in direct conflict with the design philosophy of a

multitasking operating system.

One method of single-line printing, including sample code, is provided

here. This method uses the combination of the RAW.DRV sample printer driver

and the PASSTHROUGH escape, and supports printing over a network. It has

the following limitations:

 - This method is not conducive to shared printing. If another application

   prints, it will assume that the printer is currently at the top of a

   page, which may not be the case if this code is being used.

 - This method is only compatible with dot matrix, daisywheel, or other

   printers capable of printing a single line or single line feed. It will

   not work with LaserJet printers that must print a page at a time.

MORE INFORMATION

================

If you are sure no other application will use the same printer, you can

have your application print one line at a time to a dot matrix printer

without issuing a formfeed. Use the RAW.DRV sample printer driver and the

PASSTHROUGH escape to accomplish this. Follow these steps:

1. Download RAW.DRV and place it in the \WINDOWS directory. For more

   information about RAW.DRV, including instructions for download, please

   see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q35708

   TITLE     : SAMPLE: Using a Device Driver to Send Binary Data to Printer

   Do not install this driver as the default printer driver. It is a sample

   driver and is not intended to be used for commercial applications.

2. Call the PrintLineNow function by using the following code fragment:

// The Abort Procedure for printing (a generic AbortProc)

// This procedure needs to listed be in the Exports section

//    of the .DEF file

BOOL CALLBACK AbortProc( HDC hDC, int Error )

{

  MSG msg;

  while(PeekMessage(&msg, NULL, 0, 0, TRUE))

  {

    TranslateMessage(&msg);

    DispatchMessage(&msg);

  }

  return TRUE;

}

// The function that prints one line without formfeed

BOOL PrintLineNow( char *pData, WORD cbBytes )

{

  #define   LINEBUFFER_LENGTH 80 //or dynamically alloc enough space

  HDC       hDC;

  char      pOutput[LINEBUFFER_LENGTH+sizeof(WORD)];

  DOCINFO   di;

  ABORTPROC lpfnAbortProc;

  // Buffer size is LINEBUFFER_LENGTH bytes

  if( cbBytes > LINEBUFFER_LENGTH )

     return FALSE;

  // Get the DC using the RAW.DRV driver

  if( (hDC = CreateDC( "RAW", NULL, "LPT1", NULL ) ) == NULL )

    return FALSE;

  // Set up an Abort Procedure

  if((lpfnAbortProc = MakeProcInstance(AbortProc, hInst)) == NULL)

    {

      DeleteDC( hDC );

      return FALSE;

    }

  if( SetAbortProc( hDC, lpfnAbortProc ) <= 0 )

    {

      DeleteDC( hDC );

      FreeProcInstance( lpfnAbortProc );

      return FALSE;

    }

  // Start a Document

  di.cbSize = sizeof( DOCINFO );

  di.lpszDocName = "MyDoc";

  di.lpszOutput = NULL;

  if( StartDoc( hDC, &di ) <= 0 )

    {

      DeleteDC( hDC );

      FreeProcInstance( lpfnAbortProc );

      return FALSE;

    }

  // The start of a page

  if( StartPage( hDC ) <= 0 )

    {

      DeleteDC( hDC );

      FreeProcInstance( lpfnAbortProc );

      return FALSE;

    }

  // Put data in the buffer and send to the printer

  *(WORD *)pOutput = cbBytes;

  memcpy( &(pOutput[sizeof(WORD)]), pData, cbBytes );

  if( Escape( hDC, PASSTHROUGH, 0, pOutput, NULL ) <= 0 )

    {

      DeleteDC( hDC );

      FreeProcInstance( lpfnAbortProc );

      return FALSE;

    }

  // The end of the page

  if( EndPage( hDC ) < 0 )

    {

      DeleteDC( hDC );

      FreeProcInstance( lpfnAbortProc );

      return FALSE;

    }

  // End the Document

  if( EndDoc( hDC ) < 0 )

    {

      DeleteDC( hDC );

      FreeProcInstance( lpfnAbortProc );

      return FALSE;

    }

  // Clean up

  DeleteDC( hDC );

  FreeProcInstance( lpfnAbortProc );

  return TRUE;   // Success

}

Additional reference words: 3.10 NEWFRAME FF Mailing Label Form Feed

KBCategory: kbprint kbcode

KBSubcategory: GdiPrn


PRB: Polyline Fails with NULL Clipping Region

Article ID: Q128237

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

The Polyline API will return a failure code if called on a DC that has a

NULL clipping region selected. One situation in which this can occur is

when Polyline is used to draw into a DC for a window that is completely

obscured by another window.

RESOLUTION

==========

Check to see if the clipping region is NULL before calling Polyline

and testing its return value.

STATUS

======

This behavior is by design on Windows 3.1.

This behavior does not occur on Windows NT or on Windows 95.

Additional reference words: 3.10 Polygon fails hidden

KBCategory: kbgraphic kbprb

KBSubcategory: GdiDrw


Locking Discardable Objects

Article ID: Q10220

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

It is not possible to put in a call to determine whether an object is

discarded. GlobalLock() returns NULL if the object is discarded. There is

no such thing as a swapped object. Locking a discarded object does not

affect its lock count. Discarded objects always have a lock count of zero.

Objects with a nonzero lock count are never discarded.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Heap and Stack Usage Within Windows

Article ID: Q10641

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following information clarifies heap and stack usage within a

segment versus heap and stack usage within the application as a whole,

for Windows versions 3.0 and 3.1.

MORE INFORMATION

================

An application gets a single default data segment, from which the

stack is allocated. The remainder of the data segment is used for

static data and the dynamic local heap.

The STACKSIZE keyword in the .DEF file specifies the size of the

application's stack; it is allocated from DGROUP and therefore is

limited to a maximum size of (64K - heap size - static data) bytes. The

stack size is not dynamically enlarged or reduced.

The HEAPSIZE keyword in the .DEF file specifies the initial default

local heap size. Windows attempts to enlarge the heap size when local

allocations fail; however, the heap is limited to a maximum size of

(64K - stack size - static data).

The sum of the static data, stack, and local heap cannot exceed 64K.

Multiple local heaps can be managed using the LocalInit() call and

swapping the DS register as needed. For more information on this

technique, query on the following words:

   handle and limit and globalalloc and register

Chapter 18 (pages 707-724) of "Windows 3.0 Power Programming

Techniques," by Paul Yao and Peter Norton (Bantam Computer Books),

contains more details about this technique.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


Windows: Nonpreemptive vs. Preemptive Scheduling

Article ID: Q11248

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Preemptive scheduling, which Windows DOES NOT do, is defined in the

following way:

   Between any two application instructions, N instructions may

   execute in another application's context, where N is greater than

   or equal to zero.

A nonpreemptive system, such as Windows, will guarantee that this

number N will always be zero.

MORE INFORMATION

================

In nonpreemptive scheduling, an application is not forced out of

context asynchronously (that is, it is not preempted). Instead, the

application runs until it explicitly gives up control. Windows-aware

applications give up control through various system calls. Although

they are not aware of it, MS-DOS-based applications give up control

whenever they attempt various I/O functions.

MS-DOS-based applications running under Windows version 3.0 are in fact

preemptively multitasked. In contrast, all Windows-based applications are

nonpreemptively multitasked. When the system is viewed from a Win386

perspective, Windows runs in the system virtual machine (VM) and that VM

competes for time slices along with the rest of the MS-DOS-based

applications running in other virtual machines. Keep in mind that unlike MS-

DOS-based applications, all Windows-based applications run inside the

system VM, and are not given their own virtual machine.

NOTE: An interrupt is not considered to be a form of preemption unless

there is an application context switch during the interrupt. An

interrupt takes the execution stream into the kernel, which returns

back to the same place without running another application, much in

the same way a call would.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


Reference Counts for Windows Dynamic Libraries

Article ID: Q11467

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Libraries are reference counted and remain resident in memory until

they cease to be referenced.

When a task module is started and is dynamically linked to the

library, the reference count is incremented by 1 (one). When the task

module is terminated, the reference count is decremented by 1 (one).

Two functions, LoadLibrary() and FreeLibrary(), affect the reference

count. LoadLibrary() increments the reference count by one while

FreeLibrary() decrements the reference count by one.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Definition of Different Types of Libraries in Windows

Article ID: Q11509

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

There are three different types of libraries used in Windows. These

three types of libraries are defined as follows:

1. Object libraries are produced by LIB.EXE, and consist of Intel

   object code; for example, SWLIBC.LIB (the W implies the objects

   were compiled using Windows prolog conventions).

   Object libraries, which are sometimes more accurately called static

   link libraries, are the libraries that contain object code. These

   libraries are used at link time to resolve statically linked calls.

2. DLLs (Dynamic-Link Libraries) are produced by IMPLIB.EXE and

   LIB.EXE, and contain dynamic-link records derived from GDI.DEF,

   USER.DEF, and KERNEL.DEF. They also contain the Windows startup

   routine, WINSTART.OBJ, and any routines necessary to override C

   run-time functions (for example, calloc and malloc); that is,

   Windows-specific run-time functions.

   NOTE: The term Dynamic-Link Library or DLL is usually used to

   describe the actual Windows executable that implements a particular

   API.

   The term import library is usually used to describe the product of

   the IMPLIB utility. This library is used to resolve references to

   DLL exports at the time the application is linked.

3. Executable libraries are produced by the Microsoft linker program

   (LINK.EXE), and use the keyword LIBRARY in the .DEF file. They contain

   sharable Windows code, for example, GDI.EXE, USER.EXE, or KERNEL.EXE.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


The Purpose of WINSTUB in Windows SDK

Article ID: Q11591

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

WINSTUB is provided with the Windows Software Development Kit (SDK) as

a normal MS-DOS program. It contains only an assembly equivalent to a

printf() line. It is assembly, so it does not have the overhead it

would if it used the C runtime library. WINSTUB can be used as a stub

if no MS-DOS version of a program exists. To have both a Windows version

and an MS-DOS version of a program in one .EXE file, replace the following

line in the .DEF file

   STUB 'WINSTUB.EXE'

with the following line

   STUB 'MYDOSAPP.EXE'

and relink.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


How to Transparently Intercept Procedure Calls in Windows

Article ID: Q11623

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

A technique for aliasing procedure names in Windows allows procedure

calls to be transparently intercepted. You can use this technique to

monitor activities such as checking arguments for validity.

To intercept procedure calls transparently, first build a Windows

executable code library that resembles the following:

        HANDLE MyGlobalAlloc( flags, size )

        WORD  flags;

        DWORD size;

        {

            /* Perform any type of monitoring necessary here.

               if ( !size )

                   return 0;

            */

            return RealGlobalAlloc( flags, size );

        }

        HANDLE FAR PASCAL main( argc, argv )

        WORD argc;

        LPSTR argv;

        {

            return 1;

        }

Next write the definitions file for the library above as follows:

   BOO.DEF:

   LIBRARY BOO

   DESCRIPTION "Procedure call interception library."

   DATA SINGLE MOVEABLE

   CODE MOVEABLE DISCARDABLE

   EXPORTS

          GlobalAlloc=MyGlobalAlloc

   IMPORTS

           RealGlobalAlloc=KERNEL.15

You can obtain the ordinal numbers for the KERNEL routines (or for any

other routine) by using the LIB.EXE program to list the contents of

SLIBW or MLIBW.

Build a dynamic link library (DLL) by running IMPLIB BOO.DEF as

follows:

   IMPLIB BOO.DEF BOO.LIB

Build the library executable by using the following table:

   link boo,,,mlibw mlibc,boo.def;

Next dynamically link to BOO.EXE by linking to BOO.LIB as follows:

   link car,,,boo mlibw mlibc,car.def;

Any calls to GlobalAlloc() are routed to MyGlobalAlloc() first because of

the name aliasing. This technique is very powerful and can be used to

implement any type of monitoring function. In the case of GlobalAlloc(),

the monitoring is transparent in the sense that it is not necessary to

recompile the application to remove error checking; simply link to

MLIBW.LIB instead of to BOO.LIB MLIBW.LIB.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


How to Get a Pointer to the Stack

Article ID: Q11941

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

C pushes its parameters in reverse order (right to left) for the

_cdecl calling convention (default) and in order (left to right) for

the Pascal calling convention.

The first (or last, for the Pascal convention) parameter is always the

last one pushed, and always has the same address relative to the start

of the frame.

In the C compiler documentation, see vsprintf and the va_start macro

in STDARG.H for an example of accessing variable arguments on the

stack.

To get a pointer to the stack, use the following code:

   far MyFunction()

   {

   int x;

   int far *y = &x;

   }

NOTE: This pointer will not be valid when the function is exited,

since the stack contents will change.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


How Windows Resolves Far Calls When Movable Flag Is Used

Article ID: Q11979

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The information listed below addresses the following topics relating

to using the middle model of compilation (-AM) when a module's code

segment has been renamed using the -NT switch, and the segment is

declared movable in the module definition (.DEF) file:

1. Locking of the code segment by Windows

2. The handling of FAR calls

MORE INFORMATION

================

Windows does not necessarily keep the code segment locked. The

Microsoft C Compiler uses the BP register as a "frame pointer". Local

variables and parameters are always accessed using offsets from the BP

register. The BP register is initially even, and the Windows stack is

word aligned. When a FAR call is made, BP is increased by one. If the

code segment is discarded, the stack is walked and patched. By

determining if BP is odd or even, Windows can tell whether the call is

FAR or NEAR.

When a long return address is on the stack, it has a pushed DS and BP,

and because the BP register is increased by one for FAR frames, FAR

frames may be detected by walking the task chain and BP stack-frame

chains.

When the Windows prolog is set up, it does the following:

   extern far pascal funcname();

   cProc funcname,<FAR,PASCAL>

   "cBegin"

   Prolog: push ds ; Fixed/Moveable Multiple Data Segment Support

   pop ax

   nop

   inc bp ; Far Frame Marker/Moveable Code Support

   push bp

   mov bp,sp

   push ds ; Data Context Switch Code

   mov ds,ax ; "

   ...

   "cEnd"

   Epilog: sub bp,2

   mov sp,bp

   pop ds ; Data Context Switch Code

   pop bp

   dec bp ; Far Frame Cleanup

   ret

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Windows File I/O vs. C Run-time File I/O

Article ID: Q11988

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following functions are provided by the Microsoft C Run-time Library

(CRT) and the Windows API to create a file:

   Return Type    API or Function   Category

   --------------------------------------------

   HFILE          OpenFile          Windows API

   HFILE          _lopen/_lcreat    Windows API

   int            _open/_creat      CRT

   FILE *         fopen             CRT

These return types (HFILE, int, and FILE *) are not compatible, so they can

not be used in a function which is expecting the other type. The HFILEs are

handles to operating system files (MS-DOS file handles), the ints are CRT

file handles, and the FILE *s are pointers to structures which represent a

CRT stream.

For files opened with OpenFile(), _lopen, and _lcreat, the common file

manipuluation routines that you should use are:

   _lclose

   _llseek

   _lread

   _lwrite

For files opened with _open() and _creat(), the common file manipulation

routines that you should use are:

   _close

   _lseek

   _read

   _write

For files opened with fopen, the common file manipulation routines that you

should use are:

   fclose

   fseek

   fread

   fwrite

For other input and output functions, please check the documentation for

information on whether they are intended for use with MS-DOS handles

(HFILE), streams (FILE *), or low-level I/O (int).

MORE INFORMATION

================

An application should use the OpenFile() API any time an MS-DOS file handle

is required.

The open functions do not necessarily open a file in binary raw mode; the

application is required to set the binary attribute explicitly. The

OpenFile() function automatically performs this step.

If the filename parameter specifies only a filename and extension, the open

functions search for a matching file only in the current directory.

In Windows, the OpenFile() API creates an MS-DOS file handle through which

an application can access Windows-specific files. OpenFile() initially

opens the file in binary raw mode by performing an MS-DOS Interrupt 21h

Function 3Dh. If the lpFileName parameter specifies only a filename and an

extension, OpenFile() searches for a matching file in the following

directories:

 - The current directory.

 - The Windows directory. The GetWindowsDirectory() API returns the

   path to this directory.

 - The Windows system directory . The GetSystemDirectory() API

   returns the path to this directory.

 - The directories listed in the PATH environment variable.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Fatal Error Messages 0x0140 and 0x0240

Article ID: Q12244

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

The FatalExit messages "Local heap is busy" (0x0140) and "Critical section

problems" (0x0240) indicate internal errors in Windows's memory management

routines; 0x0140 indicates an incorrect attempt to enter or leave a

critical section in the local memory manager; 0x0240 indicates that the

total number of free handles doesn't match up.

These errors shouldn't occur unless something gets destroyed; this is

usually an indication that an application is destroying memory by writing

to an area where it shouldn't.

Additional reference words: 3.00 3.10 rip dgroup

KBCategory: kbprg

KBSubcategory: KrMm


Shrinking Heap Space

Article ID: Q21581

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When an application calls LocalAlloc() and there is not enough memory

within the application's data segment, Windows will use memory from

the global heap to append this to the application's data segment.

Releasing the memory that was temporarily requested then becomes an

issue to the programmer.

For example, an initial HEAPWALK shows 12000 bytes free. After a 4K

LocalAlloc() and LocalLock(), HEAPWALK shows 4000 bytes locked and

8000 free. Then the program allocates and locks another 10K piece;

HEAPWALK shows 4000 bytes locked, 8000 free, and 10000 locked. If the

program then deallocates the 4K and 10K blocks with unlock and free,

HEAPWALK shows a free 12000 bytes and a free 10000 bytes. The

programmer then has the problem of releasing the second free 10K

block.

Using the LocalShrink() function will compact and shrink the data

segment to the smallest size possible. LocalShrink() cannot move FIXED

or locked blocks when compacting the local heap. Therefore, there may

still be free space in the heap, and the size of the heap may not be

as small as requested after calling LocalShrink(). However, this

function will compact as much as possible, given this constraint.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


How a DLL Can Display a Message Using MessageBox()

Article ID: Q22374

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, it may be necessary

for a function in a dynamic-link library (DLL) to communicate some

information to the user. The MessageBox() API is available for this

purpose.

MORE INFORMATION

================

If a function exported from a DLL displays a message box, one of the

parameters to the function should be the handle to a window in the

application that acts as the parent window for the message box. While

the message box is displayed, if Task Manager closes the parent

application for the message box, the message box is destroyed.

When a function in a DLL displays a message only in response to an

error condition, specify NULL as the value of the hWndParent

parameter, as follows:

   MessageBox(NULL, "Hi there!", "DEMO", MB_OK);

After the user dismisses the dialog box, the focus returns to the

window that previously had the focus, as above. However, because the

message box has no parent window, closing one or more applications

with the Task Manager does not destroy the message box.

Note that the hWndParent parameter must not specify a child window,

such as a control in a dialog box. If an appropriate window handle is

not readily available, specify NULL for the value of hWndParent and

specify the MB_TASKMODAL flag in the wType (fourth) parameter. This

prevents the user from interacting with any windows of the current

application without suspending other applications.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Windows Does Not Implement INT 15H to Handle Multitasking

Article ID: Q22384

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The following information describes why Microsoft Windows does not

implement an INT 15H handler to facilitate multitasking in the

presence of a NetBIOS network.

Windows does not use the INT 15H handler at all. INT 15H is specific

to the IBM PC/AT. Windows will never use an INT 15H handler because it

is designed to work on a number of different OEM machines.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrIsrTsr


Windows Does Not Support Real-Time Programming

Article ID: Q22523

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In no sense can Microsoft Windows be considered a "real-time" system.

It is a message-driven, event-polling system, with nonpreemptive

scheduling. The following is additional information:

1. It is possible to write a Windows-based application that sits on some

   interrupt in order to watch board-level activity. In general, this

   facility is used by manufacturers of boards to write drivers that

   watch and respond to interrupts used by the board. It is extremely

   dangerous to allocate/sit on any interrupt used by Windows itself

   (keyboard, mouse, etc.).

2. Dedicated systems (those that will not run general-purpose Windows

   applications) may sit on the timer interrupt, as long as Windows

   is eventually notified of the timer ticks. Because of the

   nonpreemptive aspect of the Windows system, it is insensitive to

   delays in the arrival of timer ticks. Trying to run more than one

   time-critical application that sits on the timer interrupt is

   likely to fail.

3. You must arrange for a Windows "library" of routines to provide

   access to information available from a board. The issue is one of

   how to divide the work between the following portions:

   a. The driver portion, which watches the interrupt, logs data, and

      notifies clients [through PostMessage()] of the availability of

      data

   b. The client portion, which obtains data from the driver portion,

      and processes, displays, and stores data

   Drivers can be implemented as Windows libraries, and clients of the

   device can be implemented as Windows-based applications. The driver

   portion can be made NEAR real time; the application portion is

   going to be message driven.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrIsrDll


When Can a Call to GlobalLock() Fail?

Article ID: Q30296

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The following can cause a call to GlobalLock() to fail:

1. Attempting to Lock an invalid handle.

2. Attempting to Lock an object that has been discarded. (This will

   occur if the object was allocated as discardable and the system has

   discarded it due to low memory.)

3. When an application attempts to lock a DDE object that is in

   expanded memory under low memory conditions. (This act will cause

   GlobalLock() to fail if there is not enough memory below 1 megabyte

   to allow Windows to make a copy of the object that the application

   wishes to lock. If this problem occurs, the program should free

   some of its Global memory and then try the GlobalLock() again.)

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


ValidateFreeSpaces(), GlobalCompact(), and Wild Pointers

Article ID: Q32680

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The ValidateFreeSpaces() function does not work as documented on page 4-454

of the "Microsoft Windows Software Development Kit Reference Volume 1" for

version 3.0. On page 964 of the "Programmer's Reference, Volume 2:

Functions" manual from the Windows 3.1 SDK, the ValidateFreeSpaces()

function is correctly documented.

MORE INFORMATION

================

ValidateFreeSpaces() returns a void, not a LPSTR, as documented. Under the

debugging kernel, ValidateFreeSpaces() will RIP if it finds overwritten

free space; under the retail kernel, it does nothing.

To use ValidateFreeSpaces(), the WIN.INI file must include the following

statements:

   [KERNEL]

   EnableHeapChecking=1

   EnableFreeChecking=1

If an application calls ValidateFreeSpaces() and it discovers an error, it

will RIP with a fatal exit code of 0x00ff, "FREE MEMORY OVERWRITE AT," and

the address of the byte that was overwritten as Segment:Offset.

To build a fairly solid detector of wild pointers, an application writer

can use the following statements in the [KERNEL] section:

1. EnableHeapChecking=1 to cause the kernel to regularly check the global

   arena.

2. EnableFreeChecking=1 to let ValidateFreeSpaces() check global free

   space.

3. EnableSegmentChecksum=1 to cause the kernel to check for corrupted code

   segments.

If the application then calls ValidateFreeSpaces() and GlobalCompact(-1)

regularly, it will catch almost all wild global pointers.

ValidateFreeSpaces() checks for any overwritten free blocks, and

GlobalCompact(-1) moves and discards memory, thereby forcing heap and

checksum checking.

Please note the following:

 - CCh is used for the free-space fill byte because it will cause the

   debugger to breakpoint if a jump into free space is executed.

 - If EnableSegmentChecksum=1 is used, setting breakpoints may cause

   spurious 0x0409 RIPs.

 - Setting all of these checks will noticeably slow the system.

 - If bad free spaces exist, check for fatal exit FFs and LLLLLLLs before

   the address actually appears. A few fatal exits may have to be ignored

   before the address appears.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDebug


PRB: Windows FatalExit 0x0280 Error Caused by FAR WinMain

Article ID: Q41451

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application is launched, a FatalExit 0x0280 (ERR_GMEMHANDLE,

invalid global handle) error occurs in Windows 3.0, or a general protection

(GP) fault occurs in Windows 3.1.

CAUSE

=====

The application declares the WinMain function as a FAR function. The design

of the Microsoft Windows kernel assumes that an application's entry point

is a near function rather than a far function.

RESOLUTION

==========

Remove the FAR keyword from the declaration of the WinMain function.

Additional reference words: 3.00 3.10 rip gpf gp-fault

KBCategory: kbprg kbprb

KBSubcategory: KrDebug


Calculating Memory Requirements for MS-DOS-Based Apps

Article ID: Q43041

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

It is extremely difficult for an application to determine in advance

how much memory an MS-DOS (non-Windows) application will require to run.

This data can be estimated under real and standard modes; however,

there is no method to determine this information in enhanced mode.

MORE INFORMATION

================

The Windows module WinOldAp is required to run MS-DOS-based applications.

One complication is that once WinOldAp is in memory, it can run many

applications. In the following table, "PIF Req'd" indicates the amount

of memory required for the application as listed in the corresponding

PIF file and "PIF Des'd" indicates the amount of memory desired by the

application as listed in the corresponding PIF file. The following

table indicates the difference between applications:

   PIF    PIF    Free Mem  Free Mem  Memory

   Req'd  Des'd  Before    After     Usage

   -----------------------------------------

   160    160     418      155       263     First copy run

   160    160     153      152         1     Second copy run

As this table indicates, the second copy of the application costs

almost no memory. This is because the two copies of the application

share the same memory and are swapped in and out of memory (to disk,

to a RAM drive, or to expanded memory, depending on the WIN.INI

settings).

Another factor is the order in which MS-DOS-based applications are loaded.

The statistics below demonstrate these differences. In the first case, an

80K program is loaded followed by a 160K program. In the second case,

the 160K program is loaded followed by the 80K program:

Case 1:

   PIF    PIF    Free Mem  Free Mem  Memory

   Req'd  Des'd  Before    After     Usage

   -----------------------------------------

    80     80     418      244        174     App #1 runs first

   160    160     244       37        207     App #2 runs second

                                      381     Total memory usage

Case 2:

   PIF    PIF    Free Mem  Free Mem  Memory

   Req'd  Des'd  Before    After     Usage

   ----------------------------------------

   160    160     418      154        264     App #2 runs first

    80     80     154      153          1     App #1 runs second

                                      265     Total memory usage

These results are not as unusual as they may appear. In the second

case, the larger application (App #2) is loaded first. This sets the

WinOldAp swapping partition large enough to hold the application. When

the smaller application (App #1) is run, it fits into the existing

partition. In contrast, in the first case, the smaller application is

run first, therefore the swapping area is not set large enough to hold

the larger application. When the larger application is loaded, WinOldAp

must create a completely separate partition to hold it.

The amount of memory needed to run an old application varies,

depending on the following:

1. Whether or not WinOldAp is loaded

2. Whether the existing swap area (if any) is large enough to hold it

3. Whether the application screen is saved in text or graphics mode

4. Whether large-frame, small-frame, or no EMS is in use

   (this variable does not apply to Windows version 3.1)

5. The contents of the Memory Required and Memory Desired fields in

   the PIF file

6. Other factors related to the inner workings of the Windows memory

   manager and the WinOldAp module

These methods are not applicable to enhanced mode Windows. The only

way to determine if an MS-DOS-based application will run under enhanced

mode is to attempt to run the application and see if the attempt succeeds.

Even this information is not available to another application because

the WinExec return value only indicates that WinOldAp has been

successfully loaded into memory. This value does not contain any

information regarding the real target application.

The handling of this type of problem is addressed by Windows version 3.1.

In Windows version 3.1, the TOOLHELP library can be used to retrieve the

Exit Code of a Windows-based application. This also works in Windows

version 3.0, however, the problem is that WINOLDAP (the MS-DOS-based

application's Windows agent) for Windows version 3.0 always exits with exit

code 0. Therefore, there is no way to obtain results of the attempted

MS-DOS-based application run. The version of WINOLDAP included with Windows

version 3.1 will exit with the exit code of the MS-DOS-based application

that was run, or one of the following special values:

;

; Special WINOLDAP exit codes

;

EXIT_NoFile      EQU  81h ; Could not start due to file or

                          ; directory access problem

EXIT_NoMem       EQU  82h ; Could not start due to insufficient

                          ; memory

EXIT_Crash       EQU  83h ; VM crashed (abnormal termination)

EXIT_BadVer      EQU  84h ; Could not start due to bad version

EXIT_ExecFail    EQU  85h ; Could not start because MS-DOS EXEC failed

EXIT_TaskAPIFail EQU  86h ; Could not start because task switch API

                          ; refused start (standard mode only)

NOTE THAT THESE SPECIAL CODES MAY OVERLAP WITH AN EXIT CODE USED BY

THE MS-DOS-BASED APPLICATION. If this happens, there is no way to correct

it other than to change the MS-DOS-based application to use different exit

codes that do not conflict with these special ones.

ALSO NOTE: The exit code of a .BAT file run is always 0. This is a

property of COMMAND.COM, which is part of MS-DOS.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


Applications and the Math Coprocessor Under Windows

Article ID: Q43276

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

When an application for Microsoft Windows is run on a machine with a

math coprocessor, the application can use inline floating-point

instructions to take the fullest advantage of the hardware.

MORE INFORMATION

================

Specifying the -FPi option on the C compiler command line causes the

Microsoft C optimizing compiler to produce inline 80x87 math

coprocessor code for any floating-point math operation. If this code

is linked with the WIN87EM.LIB library and a math coprocessor is

present in the system at run time, the application will use the inline

floating-point instructions for its math operations. If no coprocessor

is available at run time, code in the emulator library evaluates

floating-point expressions.

An application compiled for the MS-DOS environment with the -FPi

option checks for the coprocessor at run time and modifies its code

accordingly: if there is a coprocessor, it uses inline floating-point

instructions; if there is no coprocessor, it calls software routines

to emulate the coprocessor.

In the Windows environment, these run-time modifications are not

performed because the Windows kernel fixes up the floating point

references as it loads the application's code segments (the kernel is

aware of the presence or absence of the numeric coprocessor). This

means that an application for the Windows environment compiled with

the -FPi option will perform direct, inline floating-point

instructions without run-time coprocessor-checking. Consequently,

there is no need to link in the Microsoft C Compiler inline floating-

point module, which removes the run-time coprocessor-checking.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFltPt


Using OpenFile() with Sharing and Inheritance Bits

Article ID: Q43397

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following information describes the file-access, file-sharing, and

inheritance codes used with MS-DOS Interrupt 21h Function 3Dh that are

compatible with the Windows OpenFile() API.

A call to the OpenFile() API that specifies OF_CREATE as the value for the

wStyle parameter is translated into a call to the MS-DOS Create File with

Handle function (Interrupt 21h Function 3Ch). Because Windows does not pass

any style bits (other than OF_CREATE) to MS-DOS, the file is always created

with normal attributes.

A call to the OpenFile() API that does not specify OF_CREATE is translated

into a call to the MS-DOS Open File with Handle function (Interrupt 21h

Function 3Dh). Windows places the value of the low- order byte of the

wStyle parameter into the AL register to specify file-access and file-

sharing codes.

NOTE: The sharing bits take effect only if the MS-DOS SHARE utility is

running on a system.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Using GlobalFlags() to Test for GMEM_DISCARDABLE

Article ID: Q45704

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When testing for GMEM_DISCARDABLE, do not use the following:

   if(GlobalFlags(hMem) == GMEM_DISCARDABLE)

Instead, use the following:

   if(GlobalFlags(hMem) & GMEM_DISCARDABLE)

This is necessary because GlobalFlags() returns a one, i.e., 0x0100,

rather than 0x0F00 if the object is discardable. It is also possible

that the return value could be 0x0800 or 0x0400 or 0x0200. These cases

are also taken care of with the bitwise AND.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


How Windows Updates the LRU (Least Recently Used) List

Article ID: Q45877

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

The following information describes how the LRU (Least Recently Used)

list is updated in Windows.

When a function in a code segment is called through its thunk, one

instruction in the thunk is to update a record in the EXE header. This

is done to notify Windows that a segment has been recently accessed.

Windows updates the LRU list periodically according to the records.

The routine that does the job searches for segments that have been

accessed since the last time the routine was called. When it has been

determined that the list needs to be updated, the routine resets its

reference byte and puts it at the top of the LRU list. By default, the

updating routine is called every four timer ticks from the INT 8

handler.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


PRB: File Handles Cannot Be Shared Between Programs or DLLs

Article ID: Q46524

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

Assume that there are two applications, A and B. Application A calls a

Dynamic-Link Library (DLL) to open a file. The file pointer (FILE *pFile)

is stored on the data segment of the DLL. Application A then calls a

function in the DLL to read the record "n" of this file properly. However,

if Application B calls the same function in the DLL to read the same

record, the record appears as random characters.

RESOLUTION

==========

File handles cannot be shared between applications or DLLs. Each

application has its own file handle table. When an fopen() call

is made, a file is taken out of the application's program segment prefix

(PSP). For two separate applications to use the same file, each application

must make its own fopen() call, file I/O calls, and fclose() call.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrFileIO


Demand Paging MS-DOS-Based Applications

Article ID: Q47125

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following article has two parts. The first part applies to Windows

version 3.0, and to Windows version 3.1 without 32-bit disk access. The

second part applies to Windows version 3.1 with 32-bit disk access.

MORE INFORMATION

================

Part 1: Windows 3.0, and Windows 3.1 Without 32-Bit Disk Access

---------------------------------------------------------------

Under enhanced mode Windows version 3.0, it is not possible to allow

MS-DOS-Based applications to use virtual (demand paged) memory (VM) when

they are active (they are the foreground application, or have the

background execution option set). This is because the paging

mechanisms of the system use either:

 - MS-DOS plus an MS-DOS device plus INT13

 - Just INT13

In other words, to access the paging file (virtual memory that is

currently demand-paged out) Windows must call code that resides in

the VM along with the application (BIOS, MS-DOS, and so on).

The problem this causes is best illustrated by an example:

1. Run an MS-DOS-based application that hooks INT 13h.

2. Arrange to "page out" the page that has part of the application's

   INT 13h hook in it.

3. Touch a "not present" page.

   a. This generates a page fault.

   b. The system calls "page this page in."

   c. This calls INT 13h.

   d. This page faults because the INT 13h hook of the application is

      currently paged out.

   e. The system calls "page this page in."

   f. This calls INT 13h.

   g. This page faults because the INT 13h hook of the application is

      currently paged out.

This continues forever, causing a deadlock situation, and the system

halts.

To prevent this problem, make sure every page of an MS-DOS-based

application is always present when the application's VM is active. Thus,

MS-DOS-based application VMs are always present, and therefore, do not use

demand-paged memory except when they are not active.

Given the way that system paging works, there is no way to work around

this limitation, partly because the installed MS-DOS-based application base

is so diverse. Note also that this problem with INT 13 is only part of

the picture. Almost all hardware interrupts can cause exactly the same

problem.

Part 2: Windows version 3.1 with 32-Bit Disk Assess

---------------------------------------------------

One solution is to change the way system paging works so that to

access the paging file, the system paging does not have to use any

code that resides in the VM with the application. 32-bit disk access

for Windows version 3.1 performs this type of functionality.

32-bit disk access addresses the problem that prevents the demand

paging of MS-DOS-based application VMs. 32-bit disk access allows the

paging component of the system to access the paging file without having to

access anything that resides in the VM (the application, MS-DOS, the

BIOS, and so on). This prevents the paging deadlock problem discussed

above because all of the code and data needed to access the paging

file is inside enhanced mode Windows and is designed such that access

to the paging file will never cause a page fault to occur.

As a side benefit, this is also much faster than calling MS-DOS or

some other component in the VM because calling VM code requires that

the 80386 CPU change modes between protected mode and virtual mode.

The transitions between CPU modes are quite expensive in terms of CPU

cycles. Therefore, the other benefit of 32-bit disk access is that

there is an improvement in "paging throughput" because the "CPU mode

transitions" required by access to the paging file through MS-DOS or

INT 13h are eliminated.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


PRB: GlobalUnlock() Can Cause Fatal Exit 0x02F0

Article ID: Q49838

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

Under the debugging version of Windows, when an application calls the

GlobalUnlock() API, a FatalExit 0x02F0 "GlobalUnlock: Object usage count

underflow" error occurs.

CAUSE

=====

The application called the GlobalUnlock() API more times that it called the

GlobalLock() API. Under the retail version of Windows, the function returns

the normal value 0 in these circumstances.

RESOLUTION

==========

Match each GlobalLock() call with a GlobalUnlock() call.

Additional reference words: 3.00 3.10 fatal exit 2F0 02F0 2F0h

KBCategory: kbprg kbprb

KBSubcategory: KrMm


Failure to Load Resources When All File Handles Are Used

Article ID: Q50741

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

A Windows-based application should not use all available file handles.

Doing so may prevent Windows from being able to load the application's

resources.

When Windows has to open the application's .EXE file to retrieve a

resource (such as the icon's bitmap), it uses one of the application's

file handles. If the application has used all available file handles,

Windows cannot load the resource.

For example, suppose LoadIcon() was called previously to obtain an

icon handle successfully, and the icon is being used as a window's

icon. The rendering of the icon will fail if the application is using

all the file handles. For example, if the window is to be minimized,

the icon will be displayed as a black block on the screen.

NOTE: LoadIcon() loads in the logical information of the icon; the

bitmap of the icon is not loaded until it is going to be used.

Under MS-DOS, an application has 20 file handles when it begins

executing. Five of these handles (that is, STDIN, STDOUT, STDPRN,

STDERR, and STDAUX) are automatically opened for use by the operating

system. This leaves a total of 15 file handles available for an

application. If a Windows-based application needs more file handles open at

any given time, it can use the SetHandleCount() API.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Requested Contents for Windows Problem Reports

Article ID: Q51503

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article describes Microsoft's preferred format for submitting

problem reports on Windows. Using this format will help us to

understand the precise context of your problem report, enabling us to

provide better answers to you and more helpful problem reports to our

development staff.

MORE INFORMATION

================

Your problem report should be structured as follows:

   SEVERITY:

   ENVIRONMENT:

   DESCRIPTION:

   CONFIGURATION:

      Hardware:

      Drivers:

      Software:

   DEBUG INFORMATION:

Each of these sections is described below:

Severity

--------

1, 2, 3, or 4. Use the following guidelines for severity:

   1  Critical -- Software does not work at all (crashes) or causes

      loss/corruption of data. Any situation where the system hangs or

      requires a cold or warm boot.

   2  Major -- A feature/function does not operate as designed. Any

      command or function that produces incorrect results or renders a

      portion of the product unusable.

   3  Minor -- Problems are generally minor in nature and do not

      prevent program from running (spelling errors, screen display

      errors, and so forth), or the results are misleading and/or

      difficult for the user to understand.

   4  Enhancement -- Problem is a design or feature fault that can be

      addressed in a future release.

Environment

-----------

WINDOWS REAL or 286 PROTECT or 386 PROTECT release Version x.xx

   (Include debug info line from the bottom right of screen, if

    applicable)

Description

-----------

Below is a description of the "ideal" problem report. The best problem

reports are clear, complete, and concise. These are some points that

will make it easier to track problem reports and enter them in our

problem database.

The report should state the steps necessary to reproduce the problem,

the results, and (if available) a summary of the debug output. Try to

include enough information that we can reproduce the problem here, but

also try to keep the reports concise.

The configuration should be at the end of the problem report so that

people reading the report can get the gist of the problem without

having to wade through information that may not be relevant (but the

information is there in case it is relevant).

Configuration

-------------

   Hardware: CPU/Memory/Monitor/keyboard/printer/modem/etc.

   Drivers: Installed device drivers

   Software: TSRs/Network drivers/etc.

Debug Information

-----------------

The following is a sample of debug output that can be helpful in

locating a problem:

GENERAL PROTECTION VIOLATION

CS=0EED SS=0F35 DS=0F35 ES=OOOO FS=0000 GS=0000

   -- NV UP EI PL NZ NA PE NC

0EED:00000387  MOV     AL,BYTE PTR     AL,BYTE PTR [BX]

   DS:23D0=INV:0003

ln

No symbols found

.dg cs

004D: 0063p CODE NOTEPAD  (0EEE) 1065,103D

103D: 01FFp CODE USER     (05BE) 104D,102D

1165: 0061p CODE GDI      (03AE) 101D,100D

115D: 001Bp FREE  009D,0075

07B5: 000Bp CODE KEYBOARD (018E) 035D,0FE5

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


EMS Support in Windows Versions 3.0 and 3.1

Article ID: Q57954

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (sdk) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The information listed below discusses the following topics:

1. Windows version 3.x support of EMS.

2. Utilization of the services of an already-installed LIM EMS

   (Lotus/Intel/Microsoft Expanded Memory Support) version 4.0 driver,

   such as a "limulator" or hardware EMS board by Windows version 3.x.

3. Making EMS calls from an application not based on Windows.

4. Making EMS calls from a Windows-based application.

MORE INFORMATION

================

1. Windows version 3.x support of EMS.

   Windows version 3.x has three modes: real mode, standard mode, and

   enhanced mode. Of the three, only enhanced mode provides EMS. This

   is because "limulation" [simulation of LIM (Lotus/Intel/Microsoft)]

   requires hardware support that only the Intel 80386 provides; the

   8086 and 80286 do not have the necessary combination of protected

   mode addressing and virtual 8086 emulation (provided by the 80386's

   V86 mode).

2. Utilization of the services of an already-installed LIM EMS

   (Lotus/Intel/Microsoft Expanded Memory Support) version 4.0 driver,

   such as a "limulator" or hardware EMS board by Windows version 3.x.

   Real mode Windows can take advantage of either a limulator or a

   hardware EMS board.

   Windows version 3.0 standard mode (which runs in 80286 protected mode)

   cannot use a limulator because these drivers run in 80386 protected

   mode, thereby conflicting with the standard mode's need to switch into

   protected mode. However, if the machine has a hardware EMS board

   and associated LIM version 4.0 driver installed, any EMS calls made

   will be serviced by the EMS driver; however, Windows itself will

   not use the EMS memory in any way. Only small frame EMS is

   supported in protected mode.

   In Windows version 3.1, it is possible to start limulators such as

   QEMM, 386MAX and EMM386 in standard mode. All support for EMS from

   protected mode Windows-based applications has been dropped from Windows

   version 3.1 enhanced mode. Any INT67H calls made by a Windows

   application in enhanced mode under Windows version 3.1 will result

   in an error being returned.

   Enhanced mode is incompatible with preinstalled EMS drivers that

   cannot be "shut off" by Windows. If the EMS driver is a limulator

   that cannot be shut off, Windows will not be able to run in

   enhanced mode because the 80386 is already running in protected

   mode; limulators that can be shut off respond to Windows as it

   boots, turning themselves off and letting Windows manage the EMS

   that they had been managing.

   Physical LIM memory is not supported by 386 enhanced mode Windows.

   Software running in Virtual 8086 mode in any VM (virtual machine),

   including the system VM (which contains all the Windows

   applications), can make LIM version 4.0 calls; however, the calls

   will be handled by Windows/386, not by any previously installed LIM

   driver. No LIM calls are reflected; they are all handled (error or

   successful completion) by V86MMGR. As mentioned above, only small

   frame EMS is supported in protected mode.

3. Making EMS calls from an application not based on Windows.

   If EMS is present, MS-DOS-based applications and other applications

   not based on Windows have the full LIM version 4.0 specification

   available for their use. Running in enhanced mode, part of the mappable

   page array may not be usable; therefore, applications have to be

   sensitive to what is usable in the mappable page array and what is not;

   they cannot assume that all of the mappable page array is available.

4. Making EMS calls from a Windows-based application.

   If EMS is present, the normal small-frame EMS calls work as they do

   in Windows version 2.x (that is, applications can make LIM version

   3.2 calls plus LIM version 4.0's realloc function). This allows

   both Windows versions 2.x and 3.x applications to use EMS memory.

   CAUTION: In protected mode, the standard technique of querying for

   the presence of an EMS driver by examining the contents of

   interrupt vector 67H will fail due to virtualization of memory and

   virtualization of the IDT (interrupt description table). Therefore,

   applications will have to use the alternate technique of opening a

   file handle using the name of the EMS device driver. For more

   information on these techniques, please consult Chapter 9 of Ray

   Duncan's "Advanced MS-DOS" book (Microsoft Press, 1986), which is

   the chapter on memory management under MS-DOS. This chapter

   contains a discussion on EMS that describes how to check for the

   presence of an EMS driver.

   Windows version 3.x applications that use EMS when running in

   protected mode will be slower than non-EMS-using applications, and

   may run out of memory faster. If it is necessary to run a Windows

   version 2.x application that requires EMS under Windows version

   3.x, this can easily be done in enhanced mode. When designing a new

   application for Windows version 3.x, however, the programmer should

   take advantage of the new protected mode addressing scheme rather

   than trying to use EMS.

   CAUTION: In protected mode, the value returned as the location of

   the page frame is a selector, not a segment. Therefore,

   applications cannot make any assumptions about that value. Many

   EMS-using applications, besides encountering the inefficiency of

   using EMS, will probably run into other restrictions that will not

   allow them to run in protected mode. For example, they cannot put

   code into EMS unless they implement special handling in protected

   mode to create a code selector alias for the page frame selector.

   For enhanced mode, there are SYSTEM.INI entries that correspond to

   the same entries in the .PIF file. The Control Panel does not touch

   them. We do not expect many programmers to need to do anything with

   these at all. See the PIFEDIT documentation for information on the

   meanings of possible values.

   Example:

   ; The following variables perform the equivalent of the XMS and

   ; EMS memory PIF settings for the SYS VM:

   ;

   SYSVMEMSLIMIT           Max value (default is -1)

   SYSVMEMSREQUIRED        Min value (default is -1)

   SYSVMEMSLOCKED          Is the EMS touched under interrupt or needed

                           to be in memory at all times for some other

                           reason? (default is NO)

   SYSVMXMSLIMIT           Max value (default is -1)

   SYSVMXMSREQUIRED        Min value (default is -1)

   SYSVMXMSLOCKED          Is the EMS touched under interrupt or needed

                           to be in memory at all times for some other

                           reason? (default is NO)

   Related switch:

   EMMSIZE                 Controls the maximum amount of memory

                           that will be used for EMS across all

                           VMs (default is -1, no limit).

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrIsrTsr


Do Not Use the MS-DOS APPEND Utility in Windows

Article ID: Q58412

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The MS-DOS APPEND utility remaps the contents of specified directories

into the current directory, which makes the files of these directories

available to an application. Do not use this utility on systems

running the Windows operating environment because the APPEND utility

is fundamentally hostile to the operation of Windows. The design of

Windows rests on its ability to build a fully-qualified path for each

file it opens.

MORE INFORMATION

================

When Windows opens an application file (for example, WINWORD.EXE), it

stores the fully-qualified path of this file (for example,

D:\WINWORD\WINWORD.EXE). With this information, Windows can reopen the

file even if user or application activity changes the current drive

and current directory.

The problem with the APPEND utility is that it prevents Windows from

reliably determining the proper fully-qualified path to a file. If an

application calls the open function when C:\EXCEL is the current drive

and directory, and the D:\WINWORD directory is specified in the APPEND

search path, Windows may improperly record the fully-qualified path to

the WINWORD.EXE file as follows: C:\EXCEL\WINWORD.EXE.

In this situation, when Windows reopens the file later, it receives an

error from MS-DOS because the file is not actually located in the

drive and directory indicated by the stored fully-qualified path. When

Windows detects this error, it displays the Change Disk message box.

The APPEND utility can cause similar problems for the WINOLDAP module,

which runs MS-DOS (non-Windows) applications under Windows. These

problems can result in unexpected "File Not Found" errors, failure to

start an MS-DOS-based application, failure when the MS-DOS-based

application exits, or failure when the user tries to switch back to

Windows.

The current versions of all the major application software available

today do not require the APPEND utility. The MS-DOS version 4.0 and

4.01 installation programs usually add the APPEND utility to the

user's configuration, which consumes valuable application memory

without providing any benefits to the end user. The APPEND utility is

usually found in the AUTOEXEC.BAT file. The line with APPEND can

be removed or commented out by placing the word "remark" at the

beginning of the line.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Global Lock Count Changes in Windows 3.x

Article ID: Q61285

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The global lock count mechanism has been changed in the Windows version 3.x

protected modes (that is, standard mode and enhanced mode). The GlobalLock

function only affects the lock count of discardable objects and the default

data segment (DGROUP); movable objects are not affected. Thus, repeated

calling of GlobalLock() and GlobalFlags() on a GMEM_MOVEABLE object does

not show any changes to its lock count.

MORE INFORMATION

================

The following are reasons and explanations concerning this design change:

1. In real mode, GlobalLock() fixes the segment:offset of a global memory

   object. It also increases the lock count, as reported by GlobalFlags().

2. In protected mode, the far pointer returned by GlobalLock() is a

   selector:offset, not a segment:offset. Because the selector value does

   not change, GlobalLock() does not actually fix the memory object in the

   physical address space. Thus, the GlobalLock function in protected mode

   does not change the lock count, unless the object is discardable or is a

   default data segment.

   In the case of a discardable object, the lock count is meaningful,

   because Windows needs to know when the object can be discarded

   (which is when its lock count is zero).

3. However, some applications have used the GlobalLock() lock count

   as a "reference count" [that is, as an indication of how many times

   GlobalLock() was called]. If the lock count for an object goes to zero,

   these applications might consider the object a candidate for being

   manually discarded, perhaps after copying the data to disk.

   Unfortunately, this use of GlobalLock() as a reference count keeper does

   not work in protected mode. Applications that symmetrically pair calls

   to GlobalLock() with calls to GlobalUnlock() do not need to know the

   lock count, and therefore, are unaffected by this change in behavior.

4. How does an application keep track of reference counts now, given

   that the GlobalLock() approach does not work for nondiscardable

   objects in protected mode? The application should really keep track

   of reference counts itself, which should not be hard to do because

   the application in need of this functionality will have a table of

   global handles anyway.

   However, if the application cannot be modified to maintain its own

   reference counts, then there is a new Windows function, called

   GlobalFix(), that will accomplish this functionality. GlobalFix()

   performs the following functionality:

   a. It fixes the object in the protected mode linear space.

   b. It increments the "lock count", as returned by the

      GlobalFlags function.

5. The following includes more information about GlobalFlags(). In real

   mode, it returns the GlobalLock() lock count. In protected mode, if the

   object is discardable, GlobalFlags() also returns the GlobalLock() lock

   count. In protected mode, if the object is nondiscardable, GlobalFlags()

   returns the GlobalFix() reference count. In other words, GlobalFlags()

   always returns the lock/fix count. However, in protected mode, the

   GlobalLock() and GlobalUnLock() APIs do not affect the count, only the

   GlobalFix() and GlobalUnFix() APIs do.

   NOTE: In real mode, the GlobalFlags() lock count actually indicates

   the sum of GlobalLock()'s and GlobalFix()'es. Therefore, if the

   programmer is calling GlobalLock() and GlobalFix() in pairs,

   then the GlobalFlags() lock count actually is twice the logical

   reference count, if in real mode.

6. If the application needs to keep track of reference counts, and the

   programmer wants Windows to do the work for them, then the

   programmer must accompany every call to GlobalLock() with a call to

   GlobalFix(). This way the programmer will be able to depend on the

   validity of the GlobalFlag() lock/reference count. However, using the

   GlobalFix() API just to keep track of the reference count is overkill,

   if that is all the programmer wants it to do. Remember, GlobalFix()

   also fixes the object in the protected mode linear address space.

   The price the programmer pays for having Windows keep track of the

   reference count (by using the GlobalFix()) is the following:

   a. Every time the GlobalLock() or GlobalUnLock() API is called,

      the programmer must also call either the GlobalFix() or

      GlobalUnFix().

   And, much worse:

   b. The programmer establishes sandbars in the linear address space.

   An application should either keep track of reference counts on its

   own or always pair GlobalLock() calls with matching GlobalUnlock()

   calls; the use of the GlobalFix() API should  be avoided.

   Very few applications should need to fix global objects in linear

   space; therefore, few applications should need to use the

   GlobalFix function.

7. If the programmer needs to unconditionally unlock and free a global

   memory object of any type, then code similar to the following can

   be used:

        /* 1.  Make it discardable if necessary. */

        if (GlobalFlags shows that it is nondiscardable)

            GlobalRealloc (GMEM_MODIFY it to be discardable);

        /* 2. Remove any lock counts that might be on it. */

        while (GlobalUnlock != 0) /* keep unlocking it */

            ;

        /* 3. Free it. */

        GlobalFree()

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Why GlobalAlloc() Returns a Handle to a 0-Byte Segment

Article ID: Q61777

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When Calling GlobalAlloc() with a segment of size 0 (zero), Windows

returns a handle to the memory. Attempting a GlobalLock() using that

handle returns a NULL pointer. Since a 0-byte block of memory is

treated by the system as if it is discarded, the following explains

how these memory handles can be reused.

Consider the following scenario:

1. hMemory = GlobalAlloc (GMEM_MOVEABLE, 0L);

   This returns a handle to a block of memory of length 0 (zero).

2. wFlags = GlobalFlags (hMemory);

   wFlags is 0x4000, which is GMEM_DISCARDED. Thus, the memory object

   is thought of as if it has already been discarded.

3. lpszMemory = GlobalLock (hMemory);

   This fails. lpszMemory == 0.

4. hMemory = GlobalReAlloc (hMemory, 1L, GMEM_MOVEABLE);

   This returns the handle, and sets the size of the block to 1 byte.

5. wFlags = GlobalFlags (hMemory);

   wFlags = 0 (zero), which is GMEM_FIXED (Windows protected mode or in

   Windows 3.1, GMEM_FIXED and GMEM_MOVEABLE are the same).

6. lpszMemory = GlobalLock (hMemory);

   This returns a valid far pointer to a 1-byte buffer.

When the lock count of a GMEM_DISCARDABLE object reaches 0 (zero), it

is a candidate for discarding. If it has been discarded, it cannot be

locked or used because the memory it refers to has been deallocated.

However, it can be reallocated and then locked. As a result, the

memory handles are reused after having been discarded.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


DPMI Specification Available from Intel

Article ID: Q62065

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The MS-DOS protected mode interface (DPMI) specification is available

free of charge by calling Intel Corporation at (800) 548-4725.

International customers can obtain the DPMI Specification by

contacting the Intel sales office that serves their country.

MORE INFORMATION

================

The DPMI specification was defined to allow an MS-DOS program to

access the extended memory provided by a PC architecture computer

while maintaining system protection. DPMI defines a specific subset of

MS-DOS and BIOS calls that can be made by protected mode MS-DOS

programs. It also defines a new interface through software Interrupt

31h, which protected mode programs can use to allocate memory, modify

selectors, call real mode software, and so forth.

DPMI is commonly used to communicate with a terminate-and-stay-

resident (TSR) program or an MS-DOS device driver from a protected

mode application. If the protected mode application passes a buffer of

data to a TSR or device driver, the application must allocate the

buffer from memory addressed below 1 megabyte to make the data

accessible to the real mode software. The application must also

translate the buffer's address from a selector address to a segment

address. If the real mode software calls back to a function in the

protected mode application, the application must allocate a real mode

callback address. DPMI provides services to perform each of these

tasks.

The Microsoft Windows standard mode MS-DOS extender and Windows

enhanced mode provide translation services for most of the commonly

used interrupts. This allows a driver or an application to call

MS-DOS, the BIOS, and other common services without using the DPMI.

However, when an application communicates with a network, a TSR, or

any real mode software for which Windows does not provide automatic

translation, it must use DPMI services.

DPMI services should be used only in a Windows device driver or a

dynamic-link library (DLL). An application should manipulate selectors

using the kernel selector functions, documented in the Microsoft

Windows Software Development Kit (SDK). Calling DPMI services from an

application may not be supported by future versions of Windows.

However, calling these services from a device driver or a DLL will be

supported.

Additional reference words: 3.00 vcpi 3.10

KBCategory: kbprg

KBSubcategory: KrDpmi


Overview of How to Share Memory Between Applications

Article ID: Q64126

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Listed below are three ways to share memory between Windows

applications; these are the only methods that are guaranteed to work

in all memory configurations and in future versions of Windows:

1. Using the Clipboard

2. Storing information in the data segment of a shared Dynamic-Link

   Library (DLL)

3. Dynamic Data Exchange (DDE)

MORE INFORMATION

================

1. The Clipboard is the easiest method to use, and is discussed in

   the Windows Software Development Kit (SDK) as well as in such books

   as Charles Petzold's "Programming Windows."

2. Sharing data in the data segment of a DLL is possible because

   there is only one data segment for all instances of the DLL; DLLs

   are not "instanced." Because of this, it is possible to have the

   DLL do a LocalAlloc() out of its local heap, which is part of its

   DGROUP and thus is limited to 64K. Programmers must determine

   the memory scheme that best suits their needs and what calls they

   will make to the DLL to copy/share that memory to other applications

   that call into it.

3. DDE is designed to allow applications that follow the protocol to

   share/pass data back and forth. An "envelope and letter" analogy,

   which is listed below, provides an example of how this works:

   If some information needs to be sent from one person/application

   to another person/application, do the following:

   a. Address the envelope: Call GlobalAlloc() on a piece of global

      memory with the GMEM_DDESHARE flag.

   b. Write the letter on a piece of paper: Call GlobalLock() and

      write to the global memory.

   c. Seal the letter: Call the GlobalUnlock() function.

   d. Send the letter off to the other person: Use the PostMessage()

      function with a WM_DDE_DATA message that has the hGlobalMemory

      in it.

   To receive and read the letter, the other person/application

   does the following:

   a. Get the letter: A WM_DDE_DATA message is found in the message

      queue, along with the handle of the global memory,

      hGlobalMemory.

   b. Open the envelope: Call GlobalLock (hGlobalMemory).

   c. Make a copy of the letter and read it:

      1) Create a new envelope: Call GlobalAlloc(hNewEnvelope) and

         use the GMEM_DDESHARE flag IF the letter needs to be sent

         back.

      2) Open the new envelope: Call GlobalLock(hNewEnvelope).

      3) Copy the contents of the old letter to the new letter,

         modifying the contents at this time if necessary.

      4) Seal the envelope: Call GlobalUnlock().

      If the person/application wants to send the letter back to

      the person/application that originally sent the letter, perhaps

      with some answers to questions asked in the original letter, the

      following procedure should be used:

      5) Send the letter: Call PostMessage() with the new handle to

         global memory.

   d. When done with the old letter, throw it away: Use GlobalUnlock()

      on the handle and then call GlobalFree().

      According to the DDE specification, the rules for freeing the

      global memory object are as follows:

      Receiver deletes memory unless either of the following is true:

      1) fRelease flag is zero.

      2) The fRelease flag is 1; however, the receiving (client)

         application responds with a negative WM_DDE_ACK message.

         For more information, please refer to Chapter 15 in the

         Windows SDK reference manual.

For more information on sharing memory, please refer to Chapters 15

and 16 of the "Microsoft Windows Software Development Kit Guide to

Programming."

For more information on DDE, please refer to Chapter 22 of the

"Microsoft Windows Software Development Kit Guide to Programming."

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Windows Int 21h and NetBIOS Support for DPMI

Article ID: Q65128

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows version 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article can be found in the Software/Data Library by searching on

the keyword WINDOS, the Q number of this article, or S12684. WINDOS

was archived using the PKware file-compression utility.

NOTE: This article is part of a set of seven articles, collectively

called the "Windows 3.00 Developer's Notes." More information about

the contents of the other articles, and procedures for ordering a

hard-copy set, can be found in the knowledge base article titled "

The Windows 3.00 Developer's Notes" (Q65260).

MORE INFORMATION

================

This document provides a brief overview of the DOS Protected Mode

Interface (DPMI) version 0.9 and information on how to obtain a copy

of the specification. It also provides information on Microsoft

Windows version 3.0 support for the following:

 - Applications that use DPMI functions whether or not the application

   is based on Windows

 - MS-DOS interrupts and function requests under Windows in

   protected mode, and the degree to which they are supported

 - NetBIOS in protected mode

DPMI enables MS-DOS-based applications to access the extended memory of PC

architecture computers while maintaining system protection. It also

defines a new interface, via software interrupt 31H, that

protected-mode applications use to do such things as allocate memory,

modify descriptors, and call real-mode software.

Throughout this document and the DPMI specification, the term

"real-mode software" is used to refer to code that runs in the low

1-megabyte address space and uses segment:offset addressing. Under

Windows version 3.0 in protected mode, so-called real-mode software is

actually executed in virtual 8086 mode. However, since virtual 8086

mode is a very close approximation of real mode, both are referred to

as "real mode" in this document.

For further information on, or to request a copy of, the DPMI

specification, call Intel at (800) 548-4725.

=======================================================================

               APPLICATIONS THAT USE DPMI FUNCTIONS

=======================================================================

Windows version 3.0 running in 386 enhanced mode supports DPMI version

0.9. Windows version 3.0 running in standard mode supports a subset of

DPMI that enables applications to call Terminate-and-Stay-Resident

(TSR) programs and device drivers running in real (or virtual 8086)

mode. All code that calls DPMI directly should reside in a

Dynamic-Link Library (DLL) to ease the porting of the application to

other operating environments.

Windows-based applications should only call the following AX values for

DPMI version 0.9 functions:

   AX value       Description

   --------       -----------

   0200H          Get real mode interrupt vector

   0201H          Set real mode interrupt vector

   0300H          Simulate real mode interrupt

   0301H          Call real mode procedure with far return frame

   0302H          Call real mode procedure with Iret frame

   0303H          Allocate real mode call-back address

   0304H          Free real mode call-back address

NOTE: The table listed above differs from that in the printed copy of

the "Windows 3.00 Developer's Notes" and reflects corrections.

Windows-based applications should NOT use DPMI's MS-DOS memory management

functions. The Windows version 3.0 Kernel has two functions,

GlobalDOSAlloc() and GlobalDOSFree(), that should be used by Windows

applications and DLLs for allocating and freeing MS-DOS addressable

memory.

Other than those listed above, no DPMI functions are required for

Windows-based applications because the Kernel provides functions for

allocating memory, manipulating descriptors, and locking memory.

Applications not based on Windows that are running in 386 enhanced mode can

use all the DPMI version 0.9 functions, since they are not restricted by

the Kernel.

=======================================================================

            OTHER APPLICATION PROGRAMMING INTERFACES (APIs)

=======================================================================

In general, any software interrupt API that passes parameters in the

EAX, EBX, ECX, EDX, ESI, EDI, and EBP registers will work as long as

none of the registers contains a selector value. In other words, if a

software interrupt API is completely register-based without any

pointers, segment registers, or stack parameters, that API should work

under Windows in protected mode.

More complex software interrupt APIs require the calling function to

use the DPMI translation functions.

=======================================================================

     SUPPORT FOR MS-DOS INTERRUPTS UNDER WINDOWS IN PROTECTED MODE

=======================================================================

This section discusses support for MS-DOS interrupts and function

requests made under Windows in protected mode. This discussion assumes

MS-DOS version 3.x or later is being used.

All the MS-DOS interrupts and function requests that are not mentioned

in this section should work exactly as documented in "The MS-DOS

Encyclopedia."

UNSUPPORTED MS-DOS INTERRUPTS AND FUNCTION REQUESTS

===================================================

The following MS-DOS interrupts are not supported in protected mode

and will fail if called.

   INT         Description

   ---         -----------

   20H         Terminate program

   25H         Absolute disk read

   26H         Absolute disk write

   27H         Terminate and stay resident

The following MS-DOS INT 21H function requests are also not supported

in protected mode.

   Function    Description

   --------    -----------

   00H         Terminate process

   0FH         Open file with FCB

   10H         Close file with FCB

   14H         Sequential read

   15H         Sequential write

   16H         Create file with FCB

   21H         Random read

   22H         Random write

   23H         Get file size

   24H         Set relative record

   27H         Random block read

   28H         Random block write

   67H         SetHandleCount

PARTIALLY SUPPORTED MS-DOS INT 21H FUNCTION REQUESTS

====================================================

The following MS-DOS INT 21H function requests behave differently in

protected mode than they do in real mode. To use these function

requests, the application might require additional code.

Functions 25H and 35H, Set/Get Interrupt Vector

-----------------------------------------------

These functions set and get the protected-mode interrupt vector. They

can be used to hook hardware interrupts, such as the timer or keyboard

interrupt, as well as to hook software interrupts. Except for INT 23H,

INT 24H, and INT 1CH, software interrupts that are issued in real mode

are not reflected to protected-mode interrupt handlers. However, all

hardware interrupts are reflected to protected-mode interrupt handlers

before being reflected to real mode.

Function 38H, Get Country Data

------------------------------

This function returns a 34-byte buffer containing a double word

(DWORD) call address at offset 12H that is used for case mapping. The

DWORD contains a real-mode address. In order to call the case mapping

function, the DPMI translation function to simulate a real-mode FAR

call must be used. See the DPMI specification for more details.

Function 44H, Subfunctions 02H, 03H, 04H, and 05H

-------------------------------------------------

These I/O control (IOCTL) subfunctions are used to receive data from a

device or send data to a device. Since it is not possible to break the

transfers automatically into small pieces, the caller should assume

that a transfer of greater than 4K will fail unless the address of the

buffer is in the low 1 megabyte range.

Function 44H, Subfunction 0CH

-----------------------------

Only the minor function codes 45H (Get Iteration Count) and 65H (Set

Iteration Count) are supported from protected mode. The extensions of

this IOCTL subfunction that are used for code-page switching (minor

function codes 4AH, 4CH, 4DH, 6AH, and 6BH) are not supported for

protected-mode programs. The DPMI translation functions must be used

if it is necessary to use this IOCTL subfunction to switch code pages.

Function 65H, Get Extended Country Information

----------------------------------------------

This function is supported for protected-mode programs. However, all

the DWORD parameters returned will contain real-mode addresses. This

means that the case-conversion procedure address and all the pointers

to tables will contain real-mode segment:offset addresses. The DPMI

translation functions must be used to call the case-conversion

procedure in real mode.

=======================================================================

                          NETBIOS SUPPORT

=======================================================================

Windows supports standard NetBIOS calls in protected mode. All the

network control blocks and buffers must reside in fixed memory that is

page locked. All code that calls NetBIOS directly should reside in a

DLL to ease the porting of the application to other operating

environments.

Additional information on NetBIOS and DPMI support in Windows network

drivers is available in Chapter 6, "Network Support," in the

"Microsoft Windows Device Driver Adaptation Guide," which is part of

the Microsoft Windows Device Development Kit (DDK). Additional

information can be found in the Windows developer's note titled

"Developing Network Applications for Windows 3.00," available as

article Q65125.

Additional reference words: 3.00 Windows 3 Developer's Notes softlib

KBCategory: kbprg kbfile

KBSubcategory: KrDpmi


C Run-time Functions Can Use Far Pointers in Medium Model

Article ID: Q66462

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Far pointers to data can be used in calls to the C Run-time library

routines written using the medium model. This is often necessary

because many Windows-based applications are written using the medium model,

but must pass far data pointers to the medium model C run-time library

routines. Unless precautions are taken, passing far pointers to medium

model C Run-time routines will fail.

To use far pointers in calls to medium model C Run-time routines, the

model-independent version of the C Run-time functions must be

explicitly specified. A model-independent version of a C Run-time

function requires specification of the size of the data pointers

required (NEAR or FAR) for both function parameters and return values.

Not all C Run-time routines have model-independent versions. To

determine if a routine has a model-independent version, please consult

the header file associated with the routine or the C Run-time source

manual.

MORE INFORMATION

================

When an application is compiled using the medium memory model, the C

compiler assumes that the application will have one data segment and

multiple code segments. Because the application has only one data

segment, all pointers to data are assumed to be near pointers.

Therefore, when the compiler encounters a C Run-time function in the

source code, it automatically assumes that any pointer parameters

contain near pointers. The compiler uses the appropriate medium model

declaration for the run-time functions. This is appropriate for NEAR

data items, but many Windows API functions require or return FAR

pointers, such as GlobalLock().

To override the compiler's assumptions specify the model-independent

version of the desired routine in the application source code. The

header file associated with the routine or the C Run-time source

manual can be used to determine which C Run-time routines have

model-independent versions. Typically, the model-independent versions

of C Run-time functions are preceded by an "_n" or an "_f". For

example, strdup(), a memory model-dependent function, has two

model-independent derivatives: _nstrdup() for NEAR pointers and

_fstrdup() for FAR pointers.

When using the model-independent versions of the C Run-time routines,

the compiler will not assume that the application's data is near.

Thus, far pointers can be used in medium model applications where near

pointers would normally be used.

Unfortunately, not all C Run-time routines offer this flexibility. If

the routine does not have a model-independent version, two options are

available:

1. Write a model-independent routine that offers the same functionality

   as the C Run-time routine.

2. Copy the data into the default data segment so that near pointers,

   and the standard C Run-time routines, can be used.

One C Run-time routine that demonstrates model independence is

strncpy(). If the application source code includes a line similar to

the following

   Char_ptr = strncpy(String1, Const_String2, Count);

the compiler will use the default declaration for the routine. That

declaration is found in the header file and resembles the following:

   char *strncpy(char *string1, const char *string2, size_t);

In this situation, the data must be in the default data segment

because the routine will use the DS register when referencing both

strings.

In the same medium model applications, if one or both of the strings

are in a data segment other than the default data segment, modify the

same source line as follows:

   Char_ptr = _fstrncpy(String1, Const_String2, Count);

In this case, the compiler will use the following function declaration

   char _far * _far _fstrncpy(char _far *string1,

                              const char _far*strings,

                              size_t count);

and the application will then properly access the data in the far

segments.

NOTE: When using the same C Run-time routine in a large model application,

the default function declaration will be the model-independent version.

Thus, in the example above, the compiler will replace the call to strncpy()

with an appropriate call to _fstrncpy().

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrModls


PRB: Fatal Exit Code 0x0019 Definition and Causes

Article ID: Q66945

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

After an implicitly loaded dynamic-link library (DLL) attempts to create a

window in its initialization procedure, a Fatal Exit 0x0019 occurs.

CAUSE

=====

When an application is loaded, Windows loads any DLLs that are implicitly

referenced by that application prior to initializing the application's

task. Part of task initialization is creating a message queue for that

application. By the time the application's WinMain() function is called,

the message queue has been created.

Any window created by a DLL uses the message queue of the application task

using that DLL. If an implicitly loaded DLL creates a window in its

initialization code (that is, LibMain) there is no message queue for it to

use. When Windows detects this situation, it signals Fatal Exit 0x0019.

RESOLUTION

==========

If the DLL must display a message during initialization, it must either be

explicitly loaded from the application using LoadLibrary() or the DLL

should export a function that can be called from the WinMain() procedure of

the application. By the time WinMain() is executed, the window queue has

been created.

MORE INFORMATION

================

In Microsoft Windows, a network driver is the only DLL that can create a

window during initialization. The network driver is loaded after the first

application task has been initialized (that is, the shell), and any dialog

box displayed by a network driver uses the message queue of the shell

application.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrDll


How to Determine When Another Application Has Finished

Article ID: Q67673

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Two separate applications sometimes need to cooperate in the Windows

environment. Two Windows-based applications may work in tandem, or a

Windows-based application may require the services of a an application that

is not based on Windows.

This article examines the issues involved when a Windows-based application

requires notification that another application has completed processing.

MORE INFORMATION

================

First, the following constraints should be considered:

1. Windows was not designed to synchronize the operation of a Windows-based

   application with an MS-DOS-based application in any mode (real,

   standard, or 386 enhanced).

2. Windows does not provide any automatic way to determine if another

   application finished, or ran correctly.

This first section included below discusses techniques that can be

included in code that is written for cooperating applications (for

example, when both are Windows-based applications and when one is for

Windows and the other is not). The second section listed below

discusses techniques to apply when the other application is beyond the

programmer's direct influence.

Techniques to Use for Cooperating Applications

----------------------------------------------

The following are two options that can be used if the programmer is

developing both applications and each runs under Windows:

1. The two applications can communicate through a dynamic data

   exchange (DDE) messaging protocol that the programmer establishes.

2. Each application can register the same application-specific message

   text with Windows via the RegisterWindowMessage() function and

   receive a numeric value for the message. The terminating

   application then sends this value to the other application. This

   can be accomplished by broadcasting the message to all windows in

   the system. See the documentation for PostMessage().

When one of the cooperating applications that is being developed does

not run under Windows, the following must occur:

1. When the MS-DOS-based application completes or encounters a fatal error,

   it should write a message into a specified file in the TEMP

   directory.

2. The Windows-based application should then perform the following steps:

   a. Use the SetTimer() function to create a system timer that will

      fire at desired intervals. The estimated completion time of the

      function is one possible interval. Another would be "estimated

      time to first possible failure" if the MS-DOS-based application will

      be writing an error string for the Windows-based application to

      display.

   b. Initiate the execution of the MS-DOS-based application with the

      WinExec() function and continue with any normal processing.

   c. Upon receipt of the timer message, the TEMP directory can be

      checked to determine if a message file is present. If the file

      is present, the message in the file is parsed to see if

      termination was due to success or failure.

Techniques to Use for Third-Party Applications

----------------------------------------------

For a third-party application, the steps taken must access information

that is entirely external to the MS-DOS-based application. One possible

way to implement this method is to use the title of the WINOLDAP

window to determine if the application is still running. In this case,

the following steps should be taken:

1. Use the SetTimer() function to create a system timer. Timer

   messages should be at least a few seconds apart. This allows

   WINOLDAP to create its window and begin processing.

2. In real and standard modes, Windows-based application processing stops

   while the MS-DOS-based application is processing. In enhanced mode,

   Windows' behavior depends on the settings in the program

   information file (PIF) that corresponds with the MS-DOS

   application. For more information about the allocation of the

   processor when an MS-DOS-based application is running, query on the

   following keywords:

   prod(winsdk) and WinExec() and dependent

3. When the timer message is received, the FindWindow() function is

   then used to search for the caption of the MS-DOS-based application's

   window. The caption is created from the "Window Title" section of

   its PIF file, or if it is blank or not found, the filename of the

   old application. If the caption is no longer present, the

   application is deemed to have completed its processing.

Another possible solution is to create a batch file in MS-DOS that

checks for error level information returned from the program, and then

creates files in the TEMP directory. The Windows-based application can then

check for these "result" files to determine the MS-DOS-based application's

status.

The following batch file creates a sentinel file named BEGIN.TMP.

Until this file is deleted, the MS-DOS-based application is considered to

be running. Successful completion creates the result file, END.TMP, and

then BEGIN.TMP is deleted. An execution error creates the result file

named STOP.TMP, and then removes BEGIN.TMP.

     1:  echo start > %TEMP%\begin.tmp

     2:  MyDosApp

     3:  if errorlevel 1 goto bad

     4:  if errorlevel 0 goto good

     5:  goto end

     6:  :bad

     7:  echo bad > %TEMP%\stop.tmp

     9:  goto end

     10: :good

     11: echo good > %TEMP%\end.tmp

     12: goto end

     13: :end

     14: del begin.tmp

     15: goto end

A system timer is employed as above to direct the Windows-based application

to check for the existence of the sentinel and result files.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


Access to the Windows Clipboard by MS-DOS-Based App

Article ID: Q67675

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Windows real and standard modes do not provide an interface for

standard MS-DOS (non-Windows) applications to access the Windows

clipboard. However, in Windows enhanced mode, access is provided

through the INT 2fh interface. This article discusses various methods

that may be used to simulate clipboard access in real and standard

modes and documents the INT 2fh interface for enhanced mode.

MORE INFORMATION

================

Under Windows real and standard modes, it is possible to simulate

programmatic access to the contents of the clipboard by a standard

MS-DOS-based application. One possible method is to create a Windows-based

application that places the contents of the Windows clipboard into a

file. The MS-DOS-based application would check for the existence of the

file saved from the Windows-based application. When the file exists, the MS-

DOS-based application can read the contents, eliminating the necessity for

direct user intervention on behalf of the MS-DOS-based application.

Only textual information can be retrieved from the clipboard by a

standard MS-DOS-based application. This is done using the Edit Paste

hierarchical system menu combination in Windows enhanced mode that is

available when the MS-DOS-based application is windowed.

In Windows real or standard modes, a Paste option can be selected

directly from the system menu only when the MS-DOS-based application is

represented by an icon ("iconic"), giving the user access to its

system menu. When Paste is selected, Windows will restore the MS-DOS-based

application to full screen and paste the contents of the clipboard

where the cursor is located in the MS-DOS-based application. MS-DOS-based

applications can be made iconic in real and standard modes through an

ALT+TAB keystroke.

Placing information into the clipboard can be done though the use of

the PRINT SCREEN or ALT+PRINT SCREEN keystrokes, each of which copies

a full screen into the clipboard.

Copying information to the Windows clipboard can be done in Windows

enhanced mode using the Edit Mark and Edit Copy system menu commands.

More information on user control of the Windows Clipboard can be found

on pages 440-490 in the "Microsoft Windows User's Guide," Chapter 12.

The remainder of this article documents the INT 2fh interface to the

clipboard, available in Windows enhanced mode.

NOTE: The Windows functions RegisterClipboardFormat() and

      EnumClipboardFormats() are not supported.

Function Call Definitions

-------------------------

Name            IdentifyWinOldApVersion()

Parameters      AX = 1700H

Return Values   AX == 1700H: Clipboard functions not available

                   <> 1700H: AL = Major version number

                             AH = Minor version number

Name            OpenClipboard()

Parameters      AX = 1701H

Return Values   AX == 0: Clipboard already open

                   <> 0: Clipboard opened

Name            EmptyClipboard()

Parameters      AX = 1702H

Return Values   AX == 0: Error occurred

                   <> 0: OK, Clipboard emptied

Name            SetClipboardData()

Parameters      AX = 1703H

                DX = WinOldAp-Supported Clipboard format

                ES:BX = Pointer to data

                SI:CX = Size of data in bytes

Return Values   AX == 0: Error occurred

                   <> 0: OK.  Data copied into allocated memory.

Note            The MS-DOS-based application should call the

                ClipboardCompact() function prior to this to determine

                if the data can be accommodated in memory.

Name            GetClipboardDataSize()

Parameters      AX = 1704H

                DX = WinOldAp-Supported Clipboard format

Return Values   DX:AX == Size of the data in bytes, including any

                         headers.

                      == 0 If data in this format is not in the clipboard.

Name            GetClipboardData()

Parameters      AX = 1705H

                DX = WinOldAp-Supported Clipboard format

                ES:BX = Pointer to data buffer to hold data

Return Values   AX == 0: Error occurred (or data in this format is not

                         in the clipboard)

                   <> 0: OK

Note           This call should be preceded by a

               GetClipBoardDataSize() call to find out how much memory

               is required for the buffer. No checking is performed, the

               caller must ensure that the buffer is big enough;

               otherwise, some of the callers code or data may be

               overwritten.

Name            CloseClipboard()

Parameters      AX = 1708H

Return Values   AX == 0: Error occurred

                   <> 0: OK

Name            ClipboardCompact()

Parameters      AX = 1709H

                SI:CX = Desired memory size in bytes.

Return Values   DX:AX == Number of bytes of largest block of free memory.

                      == 0 if error or no memory

Notes           The MS-DOS-based application is responsible for including

                the size of any headers in the desired memory size.

Name            GetDeviceCaps()

Parameters      AX = 170AH

                DX = GDI information index

Return Values   AX == integer value of desired item

                   == 0 if error

Notes           The implied hDC for this call will be for the display.

Supported Clipboard Formats

---------------------------

The following Windows clipboard formats are supported:

   CF_TEXT         = 1

   CF_BITMAP       = 2         ; See structures section

   CF_OEMTEXT      = 7

   CF_DSPTEXT      = 81h

   CF_DSPBITMAP    = 82h

NOTE: Since the RegisterClipboardFormat() and EnumClipboardFormats()

      functions are not available at this time, the use of private

      clipboard formats is not supported.

Structures

----------

These structures mimic the actual Windows structures with one major

difference: instead of including a handle or pointer to other memory

containing the actual data, the data follows the structure. The

structure information now behaves like a header prefacing the data.

Bitmap structure:

   bmType          DW      ?   ; Always 0

   bmWidth         DW      ?   ; Width of bitmap in pixels

   bmHeight        DW      ?   ; Height of bitmap in raster lines

   bmWidthBytes    DW      ?   ; Bytes/raster line

   bmPlanes        DB      ?   ; Number of color planes in the bitmap

   bmBitsPixel     DB      ?   ; Number of adj color bits to def pixel

   bmBits          DQ      ?   ; Points to byte following bmHigDim

   bmWidDim        DW      ?   ; Width of bitmap in 0.1 mm units

   bmHigDim        DW      ?   ; Height of bitmap in 0.1 mm units

   BitmapData      nBytes      ; The actual data

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrIsrTsr


File Manager's Mechanism for Sensing File System Changes

Article ID: Q67725

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The Windows File Manager automatically updates its directory information

any time a Windows-based or MS-DOS-based application creates, renames, or

deletes a file.

This information is not available for use by application developers, and

there are no future plans to make this information public.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Creating a Single Import Library for Multiple DLLs

Article ID: Q68081

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

A single import library that contains information about multiple

dynamic-link libraries (DLLs) can sometimes be useful. One example in

the Microsoft Windows graphical environment is LIBW.LIB, which serves

as the single import library through which an application can link to

the Windows system DLLs GDI.DLL, KERNEL.DLL, and USER.DLL.

An import library for many DLLs can be created by supplying multiple

module definition (DEF) files as input parameters to the IMPLIB

utility. However, one must make sure that none of the exported

functions is defined in more than one DEF file. IMPLIB issues an error

message when a function name is defined more than once, which occurs

most often with the Windows exit procedure (WEP) because each DLL must

export its own WEP in its DEF file.

To avoid an IMPLIB error indicating that the WEP routine is defined

many times, create modified DEF files that do not contain EXPORT

statements for the WEP routine and specify these files as input to

IMPLIB.

MORE INFORMATION

================

Defining a function in an import library more than once creates an

ambiguity when the loader resolves references to functions exported by

other modules. For example, suppose two DLLs that share a common

import library export an Open function. When an application refers to

a function in a DLL, the loader resolves a reference to the function

(known as a fix-up) to its true address (which is not known until run

time). The DLL containing the function must be loaded to provide a

true address for its functions. However, in this example, this poses a

dilemma: because both DLLs contain an Open function, which one should

be used? Because the application's source code makes no distinction

between the two Open functions, the loader cannot resolve the

reference correctly.

To avoid the potential for ambiguity, IMPLIB issues an error message

for each function that is defined in multiple DEF files and does not

create a combined import library. Two DLLs that share a common

function name cannot share a single import library. The one exception

to this rule is the WEP function, which every DLL must export. Because

an application does not call the WEP, the function need not be listed

in the combined import library.

To create a single import library, MYIMPLIB.LIB, that can be used to

link to the three DLLs (DLL1, DLL2, and DLL3), perform the following

four steps in this order:

1. Compile and link all three DLLs as outlined in Chapter 20 of the

   "Microsoft Windows Software Development Kit: Guide to Programming"

   for versions 3.0 and 3.1. Use the original DEF file to link each

   DLL. Each file must list the WEP in its EXPORTS section with the

   RESIDENTNAME qualifier to properly export the WEP function.

2. Copy the module definition files for each DLL (DLL1.DEF, DLL2.DEF,

   and DLL3.DEF) into three dummy DEF files (DUMMY1.DEF, DUMMY2.DEF,

   and DUMMY3.DEF). These dummy DEF files are used to create the

   combined import library as outlined in Step 3 below. Do not link

   any DLL using its dummy DEF file.

3. Remove the WEP from the EXPORTS statement of each dummy DEF file.

   Only Windows calls the WEP procedure; the application does not.

   Therefore, the WEP does not need to be defined in the import

   library. Removing the WEP entries prevents an IMPLIB error about

   multiple definitions of the WEP routine.

4. Use DUMMY1.DEF, DUMMY2.DEF, and DUMMY3.DEF as input parameters to

   the IMPLIB utility, as follows:

      IMPLIB MYIMPLIB.LIB DUMMY1.DEF DUMMY2.DEF DUMMY3.DEF

The four steps above build a combined import library that contains the

linkage information required for all of the exported functions in each

of the three DLLs. It does not contain any information about any of

the WEP functions. Because applications do not call the WEP function,

this omission does not cause any linkage problems.

A dummy DEF file must not be used to link a DLL because a dummy DEF

file does not export the WEP function. Every DLL must export a WEP

that Windows can call before removing the DLL from memory.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


PRB: Cannot Exit Windows with DLL-Instanced Windows Open

Article ID: Q68552

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When the user closes the Windows Program Manager and chooses the OK

button in the Exit Windows dialog box, Windows does not close.

CAUSE

=====

A window was created in a window class registered by a dynamic-link

library (DLL), and the DLL was unloaded from the system before the

window was destroyed.

RESOLUTION

==========

Before the DLL is unloaded from the system, explicitly destroy all

windows created in a window class registered by the DLL.

MORE INFORMATION

================

When a DLL is unloaded from memory, all window classes registered by

that DLL are purged. Any windows that have been created with a DLL-

registered window class become invalid when the window class is

purged; however, these windows are not destroyed.

Sending any message to an invalid window returns zero. When Windows

sends a WM_QUERYENDSESSION message to an invalid window, the window

returns zero and Windows does not shut down. Under the debugging

version of Windows, this action creates Fatal Exit code 0x0007

messages.

This problem does not occur under Windows 3.1. When a DLL is unloaded,

before its window classes are purged, any windows created using a DLL-

registered window class are destroyed. When the debugging version of

Windows 3.1 destroys a window in this manner, it produces one of the

following four messages:

 - Module unloaded with windows still subclassed

 - Global class freed with existent class windows!

 - Window class freed with existent class windows!

 - USER: Window not destroyed

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrDll


Creating Dynamic-Linked Libraries Without Data Segments

Article ID: Q68565

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows versions

   3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Using dynamic-link libraries (DLLs) is a very flexible way to

centralize a body of program code. Many applications may use functions

from a DLL, while only one copy of the DLL code is in memory. This

contrasts with code that is statically linked into applications, which

requires each application to have its own copy of the shared code.

By default, each DLL has its own data segment, separate from that of

the calling applications. This default behavior precludes using some

of the standard Windows-application programming practices and C

run-time functions in a DLL. This article discusses techniques to

ensure that no data segment is created for a DLL.

MORE INFORMATION

================

The most common reason to use a DLL that does not have its own data

segment is to ensure that the data segment (DS) register and stack

segment (SS) register are the same (DS == SS). A large majority of the

functions provided with the C run-time libraries expect that DS == SS.

Functions with this requirement have been removed from the

DLL-specific libraries included with the Windows Software Development

Kit (SDK).

DLLs that have their own data segment will use the stack segment of

the application that calls the DLL. This means that the data segment

and stack segment differ (DS != SS). This fact precludes using many C

run-time functions and any others that require DS and SS to be the

same. A DLL without a data segment will use both the data segment and

the stack segment of the calling application; therefore, DS == SS.

The clarity of the previous discussion is complicated by the fact that

some items within a DLL will declare their own data segment. The DATA

statement in the module definition (.DEF) file is the mechanism that

Windows uses to determine if the DLL has a data segment. If the .DEF

file declares DATA NONE, then Windows will assume that no data segment

exists for this DLL. Throughout this discussion, DLLs with a DATA NONE

statement in the appropriate .DEF file will be called DATA NONE DLLs.

Since Windows assumes that a DATA NONE DLL does not have a data

segment, a data segment that is created implicitly by the DLL code

itself is not loaded into memory and will not be visible by HEAPWALK

or other heap management utilities.

When a DATA NONE DLL does have a data segment, the DLL will use the

application's DS as it should; however, the offset into the data

segment is then calculated as being relative to the DLL's data

segment. Assigning any value to a variable declared in the DLL will

then overwrite any data in the application's data segment.

This type of anomaly may be difficult to track down. When the data

segment is built for the DLL, items are placed in the data segment

from bottom to top. For example, one integer variable requires two

bytes on the bottom of the DLL's data segment. Writing to this

variable will overwrite 2 bytes on the bottom of the calling

application's data segment. Since the size of an application's data

segment is often many thousands of bytes, this type of error may go

unnoticed and will most likely not cause a general-protection (GP)

fault.

These offending data segments are created by the C Compiler to store

global and static variables and static text. One symptom of an

unexpected data segment is that the Resource Compiler provides a

warning message similar to the following:

   RC: Warning RW4002: Non-discardable Segment 2 set to PRELOAD

This warning is generated when a data segment has been created by the

C Compiler; however, flags have not been defined for that segment

(such as MULTIPLE or DISCARDABLE). The default setting for these

segments is PRELOAD SINGLE.

A DLL that uses the C run-time code references a global internal

variable __acrtused, which is declared as follows in LIBENTRY.ASM:

   extern __acrtused:abs

Referencing this variable informs the linker that the DLL will use the

C run-time code. If the C run-time code is not required by the DLL,

this line should be removed to allow a truly DATA NONE DLL to be

created.

If the C run-time code is actually used by the DLL, __acrtused must be

declared. This will cause a data segment to be created; however, the

warnings concerning that data segment may be ignored.

However, if C run-time code is not being used in the DLL, __acrtused

can be removed, and the C run-time code can also be removed from the

DLL. The C run-time code is present in the standard import libraries

xDLLCyW (where "x" is a memory model, and "y" is "E" for emulator math

or "A" for alternate math). If the xNOCRTD libraries are used instead,

no C run-time code is linked into the DLL. In addition to changing the

library specification on the LINK command line, the /NOE option must

be specified.

To use the application's DS on a function-by-function basis, the

NODATA option can be used on exports. When the linker fixes up a DLL

entry point, it can be told to omit the code that changes DS on DLL

entry. This can be done on a per-export basis, allowing much greater

flexibility because a data segment can still exist, although it is

only only set for certain calls. An example of this type of EXPORT

statement is listed below (fragment of a .DEF file):

   EXPORTS

           MyExportName @145 NODATA

When "MyExportName" is called, it will not have the DS set to the

DLL's DS, instead it will retain the application's DS.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Profiling Time Between OutputDebugString and FatalExit

Article ID: Q68624

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows versions 3.0

   and 3.1

----------------------------------------------------------------------

SUMMARY

=======

During the process of profiling an application, SHOWHITS.EXE typically

reveals that a fairly large percentage of time was spent in the

Microsoft Windows kernel between the FatalExit and OutputDebugString

functions.

This phenomenon occurs because a large amount of code between

FatalExit and OutputDebugString is not public; however, this code is

common to many public entry points. Therefore, when SHOWHITS.EXE

compares the data generated from profiling an application to the data

in the kernel symbol file, it matches the closest public symbol to the

recorded information. Because the nonpublic code is present,

SHOWHITS.EXE reports that the closest public symbols are FatalExit and

OutputDebugString. However, the application may not be spending any

time in either of these functions; instead, it may be spending time in

some private function that is located between these functions.

MORE INFORMATION

================

Because of the nonpublic code, determining exactly how much time the

application is spending in a particular block of code can be

difficult.

The GetCurrentTime function and conditional compilation can be very

helpful when timing specific sections of application code.

GetCurrentTime returns the amount of time that has elapsed since

Windows started. If an application calls this function before and

after a particular block of code, the application can generate

statistics on how much time is required for this block of code to

execute.

The following code demonstrates this idea:

// This preprocessor variable should be defined to build a profiling

// version of the application.

#define PROFILING

// This section should be either in the global variable section of the

// application or in the variable declaration section of the function

// to be profiled.

#ifdef PROFILING

   static char szProfBuf[80];

   static DWORD dwPrevTime, dwCurTime;

#endif

// This code initializes the variable and should be placed just before

// the code that is used to time a block of code.

#ifdef PROFILING

   dwPrevTime = GetCurrentTime();

#endif

// This block of code is placed after each section of code timed. It

// will display the elapsed time and update the previous time variable

// so that a number of blocks of code can be timed.

#ifdef PROFILING

   dwCurTime = GetCurrentTime();

   wsprintf((LPSTR)szProfBuf, (LPSTR)"%lu\n\r\0",

            dwCurTime - dwPrevTime);

   OutputDebugString((LPSTR)szProfBuf);

   dwPrevTime = dwCurTime;

#endif

The sample code listed above displays the elapsed time on a secondary

debugging monitor. If required, this code can be modified to write the

data to a file for analysis instead of displaying the data on a

monitor.

Additional reference words: 3.00

KBCategory: kbprg

KBSubcategory: KrDebug


Updating Cached Private Profiles (.INI Files)

Article ID: Q68827

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Under Windows version 3.1, the first time a private profile (.INI file) is

accessed, the system will call the GetFileTime() API and store this value.

The WriteProfileString() API will then call the GetFileTime() API and

compare the return value to the stored value. If the two values match, the

file is considered valid for two seconds. The function makes the changes

and writes the new contents to disk. If the two values do not match, the

profile is reread into a buffer and the change is made. The same principle

holds true for reading values from a private profile.

The reasoning behind the two second limit is that most applications read

private profiles in a burst, at application startup, and write in a burst,

at application shutdown. The penalty of one read in a twenty read sequence

is considered acceptable, given the benefits.

In Windows version 3.0, an application that has a private profile will not

respond to changes made to that private profile by a text editor. When a

text editor updates a private profile, the file on disk is modified.

However, GetPrivateProfileString() and GetPrivateProfileInt() do not read

from the disk file, instead the functions read from a copy of the file in a

cache. WritePrivateProfileString() will update the appropriate sections in

both the cached file and the disk file, however, the functions will not

reload the disk file into the cache unless the entire cache is invalidated.

The information included below discusses how to force a private profile to

be recached from a disk file.

MORE INFORMATION

================

Windows caches .INI files to reduce access time. This design allows

the file to remain in memory until a different .INI file is loaded or

until an application forces recaching of the file.

To force an .INI file to be recached, make the following call (where

<fname.ini> is the name of the application's private profile):

   WritePrivateProfileString(NULL, NULL, NULL, <fname.ini>)

This call will force the entire .INI file that is in the cache to be

invalidated. The next call to either GetPrivateProfileString() or

GetPrivateProfileInt() will cause the disk file to be recached.

While .INI files are cached to optimize access time, the following are

examples of how and when an .INI file could be recached.

1. The application could update the cache from disk each time the

   application requires information from the profile. Calling the

   WritePrivateProfileString function as outlined above would clear

   the cache.

   NOTE: Because the file is recached with every access, the benefit

   of the cache is lost with this method.

2. Create a separate program or function that the user would invoke to

   explicitly invalidate the cache. The following is some code for

   that purpose that could be placed into the GENERIC sample

   application supplied with the Windows Software Development Kit (SDK):

   BOOL InitInstance(HANDLE hInstance, int nCmdShow)

   {

      LPSTR lpApplicationName, lpKeyName, lpDefault, lpReturnedString;

      int   nSize;

      /* initialize variables */

      ...

      WritePrivateProfileString(NULL, NULL, NULL, "MY.INI");

      GetPrivateProfileString(lpApplicationName, lpKeyName,

         lpDefault, lpReturnedString, nSize, "MY1.INI");

      MessageBox(NULL, "Cache Refreshed", szApp,

         MB_ICONINFORMATION | MB_OK);

      return TRUE;

   }

   Using a program or function like this will cause the .INI file to be

   recached only when it is changed by an editor, therefore the benefit

   of the cache is retained. However, it is necessary for the user to

   call another application or function after the profile is changed

   with an editor.

3. If neither of these techniques is suitable, the application could

   check the time and date stamp on the .INI file before each access to

   see if cache invalidation is necessary. This option provides the

   benefits of the cache without requiring the user to call another

   program. The overhead required to read the time and date stamp is

   minimal compared to recaching the file with every call to either

   the GetPrivateProfileString or GetPrivateProfileInt functions.

Additional reference words: 3.00 3.10 3.x SR# G910109-169

KBCategory: kbprg

KBSubcategory: KrFileIO


Handling Critical Errors in Windows-Based Application

Article ID: Q69027

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The Windows SetErrorMode() function controls whether Windows handles

MS-DOS Function 24H errors or allows the calling application to handle

them. Listed below is an example of an MS-DOS Function 24H error and

Windows's method for handling the error: if an application attempts to

access drive A and there is no disk in that drive, Windows displays

the System Error message box "Cannot read from drive A: (Cancel)

(Retry)."

Calling SetErrorMode() allows the application to handle these messages

rather than defaulting to the System Error message box.

The following code fragment demonstrates this process:

   SetErrorMode(1);   // Allow application to handle system error

      ...

     /* If error occurs, handle it appropriately. */

      ...

   SetErrorMode(0);   // Windows will display the standard

                      // INT 24H error message box for any other

                      // System Errors.

For more information on a problem in Windows version 3.0 with extended

error handling (which was corrected in Windows version 3.1), please see the

following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q72495

   TITLE     : FIX: Bad Extended Error Info After Critical Error

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Avoid Low-Level Operations in Windows Programs: Use DLLs

Article ID: Q69756

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In the Microsoft Windows environment, an application should perform

only those operations specified by the Windows application programming

interface (API). Specifically, a Windows-based application should not:

 1. Use processor I/O instructions.

 2. Issue software interrupts.

 3. Install interrupt handlers.

These three operations should be done only in a Windows dynamic-link

library (DLL).

The Windows API has been designed to let programmers write applications in

a hardware-independent fashion. However, some programmers may have noticed

that the three operations mentioned previously can be performed from both

Windows DLLs and applications.

Therefore, it may be tempting to avoid coding these operations in a

DLL, especially if the DLL's only purpose is to execute functions that

seem to operate correctly in an application. However, Microsoft

strongly recommends against this practice, for the following two

reasons:

1. Future Compatibility. Changes may be made to Windows in future

   versions such that applications that perform these operations

   directly may not execute reliably.

2. Portability. Applications that perform these operations directly

   will be more difficult to port to different hardware platforms

   (such as Windows running on a different machine architecture).

In summary, executing low-level operations from within a Windows-based

application may, in a future version of Windows, produce unexpected

results, generate unnecessary maintenance overhead, and have severe

impact on the potential lifetime of that application. To avoid these

problems, machine-specific functionality should be coded in a DLL.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMisc


PRB: Activating Full-Screen DOS App from Icon in Enhanced Mode

Article ID: Q69895

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In Microsoft Windows enhanced mode, when an application calls the OpenIcon

or ShowWindows functions to activate a full-screen MS-DOS application from

an icon, the activation fails. These functions perform as documented in

real and standard mode.

RESOLUTION

==========

To avoid this problem, simulate the result of an ALT+TAB key combination on

the MS-DOS application icon: Send a WM_ACTIVATE message to the MS-DOS

application, and then specify its handle in a call to ShowWindow function.

For example:

   SendMessage(hDOSApp, WM_ACTIVATE, 1, MAKELONG(hDOSApp, TRUE));

   ShowWindow(hDOSApp, SW_SHOWNORMAL);

When the application sends the WM_ACTIVATE message, wParam is set to 1

because the application is being invoked by simulating the keyboard. The

high-order word of lParam is set to TRUE (non-zero) because the MS-DOS

application is represented by an icon.

The method works in all three Windows modes for windowed and full-

screen MS-DOS applications.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrWoa


Using Variable Argument Lists in DLL Functions

Article ID: Q69897

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Using variable argument lists in functions in Windows dynamic-link

libraries (DLLs) immediately suggests problems because the current

data segment is not the same as the current stack segment (DS != SS).

However, it is possible to create functions declared with the C

calling convention (_cdecl) that can properly access variable argument

lists from Windows DLLs using the Windows SDK version 3.0 or later.

MORE INFORMATION

================

In the STDARG.H file included with the Windows SDK, macros are defined

to manipulate variable argument lists. Because DS != SS in DLLs

containing code and data segments, the standard macros will not

perform properly in small-model or medium-model DLLs. The standard

macros assume that the stack segment (SS) and data segment (DS) are

equal for far-data models and use NEAR pointers to access the

arguments. However, small-model and medium-model DLLs containing code

and data segments use the calling application's SS and the DLL's DS.

The standard macros fail to account for this case.

If the DLL is a code-only DLL where DS == SS (using the DATA NONE

declaration), or if the DLL is large-model, the standard macros will

work properly.

One way to overcome the problems with the standard macros is to define

a new set of macros for use with Windows' DLLs. For example:

/****************************************************************

 *

 *      File:  wstdarg.h

 *

 *   Remarks:  Macro definitions for variable argument lists

 *             used in DLLs

 *

 ****************************************************************/

typedef char _far *wva_list ;

#define wva_start( ap, v )  (ap = (wva_list) &v + sizeof( v ))

#define wva_arg( ap, t )    (((t _far *)(ap += sizeof( t )))[-1])

#define wva_end( ap )       (ap = NULL)

/****************************************************************

 *  End of File: wstdarg.h

 ****************************************************************/

When these macros are compiled, the stack segment is properly selected

to access the arguments.

Please note the following caveats concerning the use of variable

argument lists in DLLs:

1. When passing arguments by reference, always use FAR pointer

   declarations. The compiler will synthesize FAR pointers by pushing

   the DS and the offset of the memory location on to the stack. This

   will provide the DLL will the proper information to access the

   application's data segment.

   Also note:

   If the application under development will be run under real mode,

   avoid calling functions that will yield control from the DLL. If

   yielding occurs, the data segment could be moved. Movement would

   result in invalid pointers.

2. Because functions with variable arguments are defined using _cdecl,

   all pointer arguments not declared in the parameter list must be

   typecast in the function call. If this casting is not done,

   unpredictable results will occur due to the lack of the function

   parameter prototype. For example:

   void FAR _cdecl DebugPrint( LPSTR lpStr, LPSTR lpFmt, ... )

    ...

    DebugPrint( szValue, "%s, value passed: %d\r\n",

                (LPSTR) "DebugPrint() called", (int) 10 ) ;

3. When the function is exported or imported, it must be declared with

   an underscore (_) prefix in the .DEF file. It is also necessary to

   preserve uppercase and lowercase letters in the function name.

   Here is the declaration for the function above:

    EXPORTS

       WEP          @1   RESIDENTNAME

       _DebugPrint  @2

4. Variable argument C run-time library functions such as vsprintf()

   and vfprintf() do not take into account that DS != SS. These

   functions are not available in DLLs.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


PRB: GetModuleHandle() and Long Path Causes UAE

Article ID: Q71148

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When an application calls the GetModuleHandle() API and specifies a fully

qualified path longer than 63 characters, an unrecoverable application

error (UAE) occurs.

RESOLUTION

==========

In Microsoft Windows version 3.0, the GetModuleHandle() function uses a 64

character internal buffer. In Windows 3.1, this buffer has been extended to

128 characters. Specifying a longer string overflows the buffer and causes

the UAE.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrMisc


Drive and Directory Manipulation in Windows

Article ID: Q71760

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

To get or set the current drive or directory in an application developed

for the Microsoft Windows environment, use functions provided by the

Microsoft C Run-time library. The functions listed below are compatible

with Windows and are documented in the "Microsoft Run-time Library

Reference" of Microsoft C version 6.0, Microsoft C/C++ version 7.0,

Microsoft Visual C++ version 1.0, and in the associated QuickHelp on-line

help file. Some of the functions listed below are not available in

Microsoft C version 5.1.

NOTE: Any time an application gets or sets the current drive, it

should get or set the current directory.

Function       Use

--------       ---

chdir          Changes current working directory.

_chdrive       Changes current drive.

_dos_getdrive  Gets the current default drive, using MS-DOS

               Interrupt 21h Function 19h.

_dos_setdrive  Sets the default disk drive, using MS-DOS

               Interrupt 21h Function 0Eh.

getcwd         Gets current working directory.

_getdcwd       Gets current working directory for the specified drive.

_getdrive      Gets the current disk drive.

mkdir          Makes a new directory.

rmdir          Removes a directory.

_searchenv     Searches for a given file on specified paths.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Maximizing the Use of Available Memory in Windows

Article ID: Q72236

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Windows graphical environment creates and stores objects

on behalf of each application in the system. Two places store many of

these objects, the user heap and the graphics device interface (GDI)

heap, each one limited to 64K. This article discusses the objects,

their size, and how to maximize the use of the heaps.

MORE INFORMATION

================

A good way to see what is stored in the heaps is to use the Heap

Walker tool (HEAPWALK.EXE) provided with the Microsoft Windows

Software Development Kit (SDK). Heap Walker is documented in Chapter

11 of the SDK Tools manual for Windows 3.0 and in Chapter 9 of the SDK

Programming Tools manual for Windows 3.1. The memory management

practices of Windows are documented in Chapters 15 and 16 of the SDK

Guide to Programming for Windows 3.0. Further information on Windows

memory management is available in Charles Petzold's "Programming

Windows" (Microsoft Press) and in Peter Norton and Paul Yao's "Windows

3.0 Power Programming Techniques" (Bantam Computer Books).

The following table lists the objects stored in the user heap and the

typical sizes for these items:

   Object          Size in Bytes

   ------          -------------

   Menu            20 + 20 per menu item

   Window Class    40 to 50

   Window          60 to 70

Note that every running program requires space in the user heap. Every

application must use this shared resource wisely. One technique to

reduce heap requirements is through the judicious use of resources.

For example, static strings should be placed into a string table

instead of being stored as string variables. If a group of

applications shares a common set of resources, place the resources

into a dynamic-link library (DLL). Multiple applications can share one

copy of code, data, and resources through a DLL.

Another way to reduce heap requirements is through the use of class

extra bytes and window extra bytes. Although these bytes are stored on

the user heap, each is associated with a particular window or window

class. These bytes are convenient places to store a handle to a data

structure that has been allocated from global memory.

Menus are, by far, the biggest consumer of user heap space.

Applications that have multiple menu bars or create menus with the

TrackPopupMenu() API should load these resources only as needed and

destroy them after use, instead of waiting for program termination. In

Windows 3.1, user stores menus in a separate 64K heap.

When an application creates a GDI object, Windows allocates space from

the GDI heap. While most applications create GDI objects, an

application should not create too many objects at one time. Also, each

object must be destroyed when it is no longer required by the

application. The following table lists the objects stored in the GDI

heap and their typical sizes:

   Object              Size in Bytes

   ------              -------------

   Brush               32

   Bitmap              28 to 32

   Device Context (DC) 300

   Font                40 to 44

   Pen                 28

   Region              28

   Palette             28

Items are created in the GDI heap whenever an application creates a

GDI object. Most applications create GDI objects, but an application

should not create too many objects at one time. Also, an object must

be destroyed when it is no longer required by the application.

The maximum number of windows that can be open simultaneously is

constrained by the amount of space remaining in the user heap. As

noted above, the user and GDI heaps are each limited to 64K.

Because heap space is shared among all running applications, an

application must check the value returned from each function call to

verify that memory allocations are successful. The debugging version

of Windows produces a FatalExit message when an application uses an

invalid handle. This information is difficult to obtain from any other

source.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Retrieving the Filename of an Application or DLL

Article ID: Q72385

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows environment, the GetModuleFileName function

provides the filename of the executable file that corresponds to a

given module instance handle or data instance handle.

MORE INFORMATION

================

GetModuleFileName retrieves the full path of an application or a

dynamic-link library (DLL). Specify the instance handle or module

handle of the executable hModule parameter. The syntax of this

function is:

   int GetModuleFileName(HANDLE hModule, LPSTR lpFilename, int nSize);

The hModule parameter identifies the module or instance handle,

lpFilename points to the buffer to receive the file name, and nSize

specifies the buffer size.

When Windows launches an application, its instance handle is a

parameter to WinMain. For a DLL, the instance handle is a parameter to

LibMain. The instance handle is also available through the GetWindow

function, as follows:

   // hWnd is a handle to any one of the target

   // executable file's windows or controls.

   hAppInstance = GetWindowWord(hWnd, GWW_HINSTANCE);

   nPathLength = GetModuleFileName(hAppInstance,

                    (LPSTR)szPath, PATH_LENGTH);

The GetModuleHandle function provides the module handle for a

specified module. For example, if Microsoft Excel is loaded, the full

path to the Excel executable file is available through the following

code:

   // "EXCEL" can be used instead of "EXCEL.EXE".

   hModule = GetModuleHandle("EXCEL");

   nPathLength = GetModuleFileName(hModule,

                    (LPSTR)szPath, PATH_LENGTH);

Given a handle to a window or control in an application, the

GCW_HMODULE parameter to the GetClassWord function provides the

application's module handle.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMisc


Shorthand Notation for Memory Allocation Flags

Article ID: Q72459

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Some flags have been defined in the WINDOWS.H file [distributed with

the Windows Software Development Kit (SDK)] that are designed to be

used instead of common flag combinations for memory allocations.

Included below is an explanation of these flags:

Global Memory Allocations

-------------------------

There are two flags defined for global memory allocation: GHND and

GPTR. Both are to be used for the wFlags parameter of the

GlobalAlloc function.

   Flag      Definition

   ----      ----------

   GHND      (GMEM_MOVEABLE | GMEM_ZEROINIT)

   GPTR      (GMEM_FIXED | GMEM_ZEROINIT)

Local Memory Allocations

------------------------

Similarly, there are two flags defined for local memory allocation:

LHND and LPTR. Both are to be used for the wFlags parameter of the

LocalAlloc function:

   Flag      Definition

   ----      ----------

   LHND     (LMEM_MOVEABLE | LMEM_ZEROINIT)

   LPTR     (LMEM_FIXED | LMEM_ZEROINIT)

The LPTR flag returns a pointer that can be used immediately (no need

to call the LocalLock function); whereas with the GPTR flag, the

GlobalLock function still must be used on the handle that is

returned.

For more information on the GlobalAlloc and LocalAlloc functions,

refer to the "Microsoft Windows Software Development Kit Reference

Volume 1".

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Determining That SHARE Is Loaded Under Microsoft Windows

Article ID: Q72744

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

To determine whether the SHARE.EXE application is loaded, an application

typically calls MS-DOS Interrupt 2Fh Function 1000h. However, this method

always returns true in enhanced mode Microsoft Windows versions 3.0 and 3.1

even if the SHARE is not loaded.

Windows returns true for Interrupt 2Fh Function 1000h to prevent SHARE

from installing itself in an MS-DOS virtual machine (VM) under Windows.

If SHARE installed a local copy in a VM, the system would become

unstable and data corruption on the hard drive(s) might result.

MORE INFORMATION

================

To determine under enhanced mode Windows whether SHARE is installed,

call Interrupt 21h Function 5Ch to lock a region of a file. This

function is available only when SHARE is installed, and unlike using

the OpenFile function with sharing modes, the lock region function

always fails with error 1 (invalid function) if SHARE is not loaded.

Perform the following six steps to determine whether SHARE is loaded:

1. Create a temporary file using MS-DOS Interrupt 21h Function 5Ah.

2. Lock a region of the returned temporary file using MS-DOS Interrupt

   21h Function 5Ch. Set AL = CX = DX = SI = 0 and DI = 1.

3. If the call in step 2 returns with the carry flag set and AX = 1,

   SHARE is not loaded. Move to step 5.

4. SHARE is loaded. Unlock the region of the file using MS-DOS

   Interrupt 21h Function 5Ch. Set CX = DX = SI = 0 and AL = DI = 1.

5. Close the file using MS-DOS Interrupt 21h Function 3Eh.

6. Delete the file using MS-DOS Interrupt 21h Function 41h.

Note that the drive on which the temporary file is created is

important in a network environment. Typically, SHARE is always loaded

for network drives; however, a copy of SHARE is running on the server,

not on the workstation. Therefore, the application should run the test

above against the drive(s) from which it will access files.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


WINMEM32 Not Version Dependent

Article ID: Q73666

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

WINMEM32 is a dynamic-link library (DLL) designed to run in Microsoft

Windows enhanced mode to provide support for 32-bit flat memory model

code under Windows. While WINMEM32 is not bound to a particular

version of Windows, it does require enhanced mode.

New versions of WINMEM32 that might become available in the future

should not affect the ability to use old versions of WINMEM32 on a

given system. Note, however, that only one version of WINMEM32 can be

loaded at a time.

Newer versions of WINMEM32 will be backward compatible with older

versions. Because you should upgrade to the new version, if possible,

it is very important that WINMEM32 applications do not tightly version

bind to WINMEM32. An application should always use the greater-than-

or-equal-to operator (>=), never the equal-to operator (==), to

compare the result of the WINMEM32 GetWinMem32Version function to the

required version.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


MS-DOS-Based Application Characteristics Under Windows

Article ID: Q73668

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article discusses the mechanism that the Microsoft Windows graphical

environment uses to run an MS-DOS (non-Windows) application.

MORE INFORMATION

================

In the Window environment, each MS-DOS-based application runs has a

Windows-based application to act as its agent. When the MS-DOS-based

application is running in a window under enhanced mode Windows, and the MS-

DOS-based application makes a call to the display hardware, the agent

intercepts the call and places the character into its window. To the

MS-DOS-based application, the agent acts as a virtual copy of the display

hardware.

NOTE: The Windows agent does not manage the display; it simply renders

the MS-DOS-based application's display into a window.

To determine if an application is an MS-DOS-based application, check the

application's name to see if it matches the name of the MS-DOS-based

application agent. The module name of the MS-DOS-based application agent is

WINOLDAP. The following code fragment performs this check:

   BOOL IsThisWOAWindow(HWND hWnd)

   {

      BOOL IsWOA;

      HANDLE hModWOA;

      IsWOA = FALSE;

      if (hModWOA = GetModuleHandle("WINOLDAP"))

         {

         if (hModWOA == (HANDLE)(GetClassWord(hWnd, GCW_HMODULE)))

            {

            IsWOA = TRUE;

            }

         }

      return IsWOA;

   }

To determine how many MS-DOS-based applications are running at any given

time, call the code above from an loop that enumerates the handles of

all windows in the system.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


Allocation Limit on WINMEM32 Global32Alloc() Function

Article ID: Q73677

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

WINMEM32 is a dynamic-link library (DLL) that is designed to support

the 32-bit flat memory model under Windows enhanced mode.

The largest block of memory that Global32Alloc() can request is (16

megabytes -- 64K). Global32Alloc() allocates memory through the Windows

kernel, which imposes this particular size limitation.

Adding the ability to process larger allocations is under consideration for

a future version of Windows.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Appropriate Uses of WINMEM32

Article ID: Q73679

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

WINMEM32 is a dynamic-link library (DLL) that supports 32-bit flat

memory under the Microsoft Windows graphical environment. WINMEM32

provides a flat model computing environment for applications ported

from another operating system to Windows. New applications should not

be designed using WINMEM32.

MORE INFORMATION

================

WINMEM32 is designed for an application structured as follows:

      +------------------------+

      |       Front End        |

      | Performs all           |

      | interaction with I/O   |

      | devices, the user, and |

      | the operating system.  |

      +------------------------+

                 /\

                 ||

                 ||

                 \/

      +-----------------------+

      | Computation Engine    |

      +-----------------------+

The front end application that provides the user interface is a

standard application for the 16-bit Windows environment. WINMEM32

supports the 32-bit "computation engine" that has no user interface

and does not interact with any peripheral devices or the operating

system.

Windows is not designed to support 32-bit applications; WINMEM32 is a

temporary measure to support an independent software vendors (ISV)

with a substantial investment in 32-bit code developed for another

operating system. Even with WINMEM32, porting an application to

Windows involves many complex issues that an ISV must carefully

address for the application to work properly.

Future versions of Windows will address the 32-bit application issues

better than WINMEM32 does. Future versions of Windows will support

WINMEM32 applications even though WINMEM32 is not developed any

further.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Ownership of Global Memory Allocated by a DLL

Article ID: Q74040

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows environment, when a function in a dynamic-

link library (DLL) calls the GlobalAlloc function without specifying

the GMEM_DDESHARE flag in the wFlags parameter, the returned global

memory object belongs to the currently active instance of the

application that called the DLL. If that instance of the application

terminates, the memory is freed. If the DLL is unloaded before the

application terminates, the memory remains allocated.

If the function specifies the GMEM_DDESHARE flag when calling the

GlobalAlloc function, the DLL owns the returned memory object. The

memory is freed when the DLL is unloaded, not when any application

terminates.

This behavior will continue for 16-bit applications in all future

versions of the Microsoft Windows graphical environment. However,

applications written for Windows NT may be required to free

GMEM_DDESHARE memory explicitly by calling the GlobalFree function. In

other words, the system may not free GMEM_DDESHARE memory when either

the DLL or the application terminates.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Minimizing Lock and Unlock Calls in Protected Mode

Article ID: Q74197

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

When Microsoft Windows is running in protected mode (standard mode or

enhanced mode), the selector of a movable memory block does not change

even though Windows may move the block in physical (standard mode,

enhanced mode) or linear (enhanced mode) memory.

Applications that run only in protected mode can take advantage of this

behavior to minimize the number of GlobalLock() and GlobalUnlock() calls.

MORE INFORMATION

================

The following code demonstrates how to allocate a global memory object:

   HANDLE hMem;

   LPSTR lpstr;

   if ((hMem = GlobalAlloc(GMEM_MOVEABLE, cb)) != NULL)

      if ((lpstr = GlobalLock(hMem)) != (LPSTR)NULL)

         {

         // use the memory

         }

The following code demonstrates how to free the global memory object

allocated above:

   if (GlobalUnlock(hMem) != (HANDLE)NULL)

      GlobalFree(hMem);

Leaving movable global memory objects locked does not impose a memory

consumption penalty in protected mode.

This technique is not appropriate for an application that runs in real

mode under versions of Windows prior to version 3.1. In real mode,

Windows manages a limited amount of memory (less than 640K) by moving

and discarding memory blocks. When an application locks a memory

block, Windows cannot move or discard the block. Therefore, an

application that runs in real mode must lock an object only while the

object is in use.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Some Windows Functions Cannot Be Called from LibMain

Article ID: Q74288

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, when a dynamic-link

library (DLL) is implicitly linked to an application, the LibMain

function in the DLL should not call any dialog box, messaging, or

window management functions. Making such a call causes a FatalExit

error under the debugging version of Windows because the application

has not created a message queue when the LibMain function for an

implicitly loaded DLL executes.

MORE INFORMATION

================

Every Windows DLL must include an automatic initialization function,

which is typically called LibMain. Windows calls this function when

the DLL is initially loaded, giving the DLL an opportunity to perform

one-time startup processing.

This startup processing typically includes registering window classes,

initializing the DLL's local heap, and setting initial values for the

DLL's global variables. However, a DLL's LibMain function cannot

safely make many Windows calls.

When Windows loads an application that is implicitly linked to a DLL,

it also loads the DLL on behalf of the application. Windows loads the

DLL and calls the DLL's LibMain function before calling the

application's WinMain function and before creating the application's

message queue.

While the DLL is executing, it uses certain system resources that are

owned by the application. One of these resources is the application's

message queue. If the application's message queue has not been

created, the DLL cannot do any messaging or tasking (because these

operations require a message queue). In other words, the DLL cannot

call any Windows functions that would send a message or yield control

to another application. Attempting to do so causes a FatalExit error.

Because the DLL's LibMain function may be called before the

application's message queue is created, the LibMain function cannot do

any messaging or tasking. Such calls include the dialog box, messaging

and window management functions as well as other functions that could

result in a message being sent.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Three Methods to Import Functions from a DLL

Article ID: Q74360

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, an application can

import a function from a dynamic-link library (DLL) in three different

ways:

 1. Implicitly at link time

 2. Explicitly at link time

 3. Dynamically at run time

Importing at link time is the simplest and the most commonly used.

While importing at run time is cumbersome, it is the most powerful and

it should be used if the link is not certain to succeed.

MORE INFORMATION

================

An application implicitly imports a DLL function at link time when the

import library for the DLL is listed on the linker command line for

the application. For example, an application implicitly links to

Windows functions because its linker command line includes LIBW.LIB.

An application explicitly imports a DLL function at link time when the

IMPORTS section of the application's module definition (DEF) file

includes the name of the function.

Both methods are easy to use because the application can call an

imported function as if it were part of the application.

However, in certain situations, importing at link time has drawbacks.

For example, if the DLL is not found when Windows loads the

application, Windows displays a system-modal message box: "please

insert (a disk with the DLL) in drive A." Therefore, an application

should not perform an implicit import at link time if the DLL may not

be present.

Another situation in which importing at link time is not appropriate

occurs when the application needs to import a routine that is not

exported by all versions of the DLL. An attempt to link to an invalid

export ordinal results in an unrecoverable application error (UAE).

Both of these situations are addressed by importing the function at

run time. An application does this by calling the LoadLibrary function

to load the DLL and then calling the GetProcAddress function to

retrieve the address of the required function. The application should

check the values returned from LoadLibrary and from GetProcAddress to

ensure that these functions succeed. If the DLL is not found or does

not export the desired function, one of these calls fails, and the

application can handle the error gracefully.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


PRB: Fatal Exit 0x00FF or 0xD000: MakeProcInstance Fails

Article ID: Q74363

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

An application running under the Microsoft Windows graphical environment

receives FatalExit error 0x00FF or 0xD000, "MakeProcInstance only for

Current Instance."

CAUSE

=====

A function in a dynamic-link library (DLL) calls the MakeProcInstance()

function using an application's instance handle. The FatalExit() occurs

because the current value of the DS register does not match the instance

handle passed to MakeProcInstance().

RESOLUTION

==========

A DLL should not call MakeProcInstance() on behalf of the calling

application. The MakeProcInstance() function is not designed to be used

this way.

MORE INFORMATION

================

When an application is executing, the value of the DS register is

equal to the application's data segment, which is identified by the

application's instance handle.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrDebug


Steady Timer Messages in a Dynamic-Link Library (DLL)

Article ID: Q74412

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, a dynamic-link library

(DLL) can receive steady timer messages, even as various applications

that link into the DLL are started and terminated. However, it cannot

do so by calling the SetTimer() API directly as an application

typically does. To receive steady timer messages, a DLL can launch a

hidden application and use that application's message queue to receive

the timer messages.

MORE INFORMATION

================

The SetTimer() API is used to create a Windows timer. When the timer

expires, Windows needs a message queue into which it can place a WM_TIMER

message. A message queue is required even if a timer notification function

is specified as the lpTimerFunc parameter to SetTimer().

Because a DLL is not a task, it does not have a message queue. When a

DLL calls SetTimer(), Windows places the resulting WM_TIMER messages

into the message queue of the currently active task, which is the

application instance that called into the DLL.

If this application instance should terminate, its message queue is

destroyed, and the DLL does not receive any more timer messages. If

the DLL specified a timer notification function, the notification

function is not called again.

For a DLL to receive a steady flow of timer messages, the timer

messages must go into a message queue that will remain present while

the various applications that link into the DLL are started and

terminated. One way to achieve this is to launch a hidden application

from the DLL. The DLL can use that application's message queue to

receive steady timer messages.

This technique could be implemented as follows:

1. Export a routine from the DLL with syntax similar to the following:

      void FAR PASCAL StartDLLTimer(HWND hWndHiddenApp)

2. To start a steady timer, the DLL launches a hidden application with

   a call similar to the following:

      WinExec("MYTIMER.EXE", SW_HIDE);

   MYTIMER is a minimal Windows-based application. The only special

   processing MYTIMER requires is to link to the DLL and call the

   StartDLLTimer function in the processing of its WM_CREATE case,

   supplying the handle for its main window as the value for the

   hWndHiddenApp parameter.

3. In the StartDLLTimer function, the DLL calls SetTimer, specifying

   hWndHiddenApp as the hWnd parameter.

Timer messages for the DLL consequently use the MYTIMER function's

message queue. Therefore, the DLL continues to receive timer messages

regardless of other applications that link into the DLL.

Timers are a scarce system resource. If the SetTimer() call fails, no

timers are available for use.

Before the DLL terminates, it should free the timer. It can do so by

calling KillTimer(). It then sends a WM_CLOSE message to the MYTIMER

application, which terminates MYTIMER.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Opening Files, Compatibility Mode and Windows

Article ID: Q74445

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Opening a file in compatibility mode is a very unfriendly action in a

multitasking environment such as Windows. There is never any need to

do so; compatibility mode provides support for old MS-DOS

(non-Windows) applications however it does not provide additional

functionality.

Use the following four guidelines for opening files:

1. Do not use the _lcreate function, it opens files in compatibility

   mode. If it is necessary to create a file, immediately close the

   file and then reopen it with the _lopen function.

2. Do not use the OF_SHARE_COMPAT option with the _lopen or OpenFile

   functions. Instead, use one of the other OF_SHARE defines. If no

   OF_SHARE value is specified, the file is opened in compatibility

   mode.

3. When creating a file using MS-DOS interrupts 3Ch or 5Bh, after

   creating the file, close it and then open it again. The create

   leaves it in compatibility mode.

4. When opening a file (MS-DOS interrupts 3Dh or 6Ch), make sure that

   the file is NOT opened in compatibility mode.

When specifying the open mode and share, do not request more access

than required. If a file will only be read, open it in read-only mode

EVEN IF EXCLUSIVE ACCESS IS REQUESTED. Do not lock out other access

unnecessarily. If an application will only read a file, allow other

applications to read the file as well.

Finally, be open to alternatives when opening a file. If a file is

being opened to display its contents and an open READ-ONLY, DENY-WRITE

fails, try an open READ-ONLY, DENY-NONE.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Using Memory Below 1 Megabyte

Article ID: Q74696

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Memory allocated with a base address below 1 megabyte (low memory) is

useful for communicating between applications developed for the

Microsoft Windows graphical environment and MS-DOS terminate-and-stay-

resident (TSR) programs and device drivers.

The only way a Windows-based application can directly allocate memory

guaranteed to be below 1 MB is to use the GlobalDosAlloc function.

However, this memory is a limited resource and should be used with

care.

MORE INFORMATION

================

The following clients use memory below 1 MB:

 - MS-DOS

 - MS-DOS device drivers

 - TSRs

 - Parts of the Windows kernel

 - Windows enhanced mode virtual drivers (VxDs)

 - Windows-based applications that call GlobalDosAlloc

 - Windows-based applications that call GlobalAlloc and receive low memory

   by chance

 - The task database for each active Windows-based application (This small

   block of low memory holds data used by MS-DOS.)

The first four clients on the list allocate their memory before any

Windows-based applications are run, therefore an application cannot prevent

this consumption of the low memory resource. (The user can modify the

CONFIG.SYS and AUTOEXEC.BAT files to reduce the number of devices and

TSRs.)

Virtual devices can allocate (or map) memory below 1 MB to communicate

with various hardware devices and MS-DOS device drivers. VxDs such as

the virtual NetBIOS driver and various virtual display drivers map

memory below the 1 MB line, reducing the amount of low memory

available to Windows.

The last three clients of low memory listed can progressively consume

more of the resource as the system runs, therefore an application can

increase the chance that its low memory allocations will succeed by

performing them as early as possible during system initialization. Two

methods for doing this are:

1. Load the application or dynamic-link library (DLL) from the "run="

   or "load=" line in the WIN.INI file or from the StartUp group

   provided by Windows 3.1, or

2. Create a Windows device driver that performs the allocation when it

   is first loaded.

Beware of using too much low memory because other applications that

need low memory may begin to fail. The worst outcome of allocating too

much low memory is that Windows will be unable to allocate the task

database required to start an additional application.

In Windows enhanced mode, the lower memory that Windows-based applications

allocate is local to the system virtual machine (VM). Other virtual

machines (or MS-DOS compatibility boxes) cannot see the memory that

the GlobalDosAlloc function allocates. Allocating "global" low memory

(seen by all virtual machines) requires a virtual device, or the

memory must be allocated before Windows is loaded.

Additional reference words: 3.00 3.10 meg

KBCategory: kbprg

KBSubcategory: KrMm


Using a TSR to Share XMS Memory Between Virtual Machines

Article ID: Q74809

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

By using a terminate-and-stay-resident program (TSR) loaded before

Windows, programs can share a block of extended memory specification

(XMS) memory between virtual machines (VMs).

When the TSR is loaded, it allocates and locks a block of XMS memory.

This memory is now global to all VMs. The TSR hooks an interrupt and

will return the physical address of the block and the XMS block

handle.

A protected-mode Windows program can access the memory directly by

converting the physical address returned by the TSR to a linear

address using DPMI (the MS-DOS Protected Mode Interface). This linear

address can then be used to build a descriptor that references the

memory. The descriptor is also built using DPMI.

For the MS-DOS VM to access the XMS block, it must use the XMS block

handle returned by the TSR. With this handle, MS-DOS-based applications can

copy data to and from the block.

A sample application that demonstrates the techniques outlined above

is available in the Software Library in XMSWIN.EXE. A copy of the

Microsoft Macro Assembler (MASM) version 5.0 or later is required to

build the applications in this file.

Download XMSWIN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for XMSWIN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download XMSWIN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get XMSWIN.EXE

Additional reference words: 3.00 3.10 softlib XMSWIN.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrIsrTsr


How to Start a Windows-Based App Directly from MS-DOS

Article ID: Q74887

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

---------------------------------------------------------------------

SUMMARY

=======

It is possible to create a Windows-based application that can be started

directly from the MS-DOS prompt. For example, the KILLERAP application

may be written so that when KILLERAP is typed at the MS-DOS prompt,

Windows is loaded and KILLERAP run.

However, some specific programming is required to perform this task.

Otherwise, enhanced mode Windows will produce a "Memory Segmented"

error message. This article discusses the techniques required.

MORE INFORMATION

================

The "Memory Segmented" error message is caused by the fact that the

application that spawns Windows remains in memory when Windows loads.

There is a straightforward way to work around this complication.

Replace the standard WINSTUB.EXE program, provided with the Windows

Software Development Kit, with a custom program tailored to the

application.

The following sample WINSTUB program loads the string "win notepad"

into the keyboard key buffer. Then the program terminates and is

removed from memory. The keystrokes in the key buffer are played back

by the hardware to MS-DOS. This starts Windows and runs the program.

This sample code requires Microsoft C version 6.0 or later to compile

because it uses inline assembly code. A similar program may be written

with the Microsoft Macro Assembler (MASM) version 5.1 or later.

Sample Code

-----------

void main(void)

{

  char szExecLine[] = "win notepad\r";

  int  iIndex;

  char cChar;

  for (iIndex = 0; iIndex < sizeof(szExecLine); iIndex++)

    {

    cChar = szExecLine[iIndex];

    _asm

       {

       mov        ah, 05h

       mov        ch, 0

       mov        cl, cChar

       int        16h

       }

    }

}

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Sharing Windows-Based Applications Across Networks

Article ID: Q74890

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When writing Windows-based applications that may be placed on a network, it

is necessary to consider the demands of the MS-DOS SHARE utility and of the

network when designing the application.

If the application is written to conform to the normal MS-DOS INT 21H

protocol and the network supports shared access, then the application

will run properly. Most network vendors implement some kind of file

sharing system that handles multiple files accessed across the

network.

In many cases, network applications are not tested properly. It is

necessary to test the worst-case scenario, where the same file is

opened by more than one workstation simultaneously and manipulated

using standard file I/O instructions (read, write, close, and so

forth).

When the MS-DOS SHARE utility is run from a workstation, only the files

on that workstation are shared. However, if SHARE is not run on the

network server, applications will encounter problems. All Microsoft

LAN Manager servers load SHARE so that file sharing is virtually

transparent to the user. It is the user's responsibility to verify the

network's implementation of shared files.

The "IBM DOS Technical Reference" shows the normal file operations

table. This should be used as the guideline when network applications

are implemented.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDosint


Keeping MS-DOS-Based App Active Under Windows 3.1

Article ID: Q74940

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

A brief discussion of how an MS-DOS-based application running under Windows

standard mode can prevent a task switch is provided below. For a more

detailed discussion, refer to Chapter 7 in the "MS-DOS Programmer's

Reference" version 5.0 manual.

MORE INFORMATION

================

The switcher API enables a conversation between a task switcher and

one or more other pieces of software called respondents/clients. Each

respondent is expected to provide a call-out function entry point. The

switcher calls this function to get information from the respondent.

The switcher also provides the responder with a call-in function,

which the responder can call to query the switcher.

The switcher builds a chain of respondents through the Build Call-Out

Chain call. This is an INT 2Fh call specified below:

On Entry: AX = 4B01H

          ES:BX = 0:0

          CX:DX = call-in address of the switcher

On Exit:  ES:BX = address of client's Switch_Call_Back_Info (SCBI)

                  data

Switch_Call_Back_Info is defined as follows:

Switch_Call_Back_Info STRUC

  SCBI_Next      dd   ?    ; pointer to next client in the chain.

  SCBI_Entry_Pt  dd   ?    ; Call-Out function address of the client

  SCBI_Reserved  dd   ?    ; reserved for future use.

  SCBI_API_Ptr   dd   ?    ; pointer to list of asynchronous API info.

Switch_Call_Back_Info ENDS

When the call is received by a responder, it should first call the

previous INT 2FH handler. The returned ES:BX should be saved in the

SCBI_Next field of its SCBI structure. After initializing the other

fields of the structure, return from the interrupt with ES:BX pointing

to its SCBI structure.

The call-in function of the respondent will now be called every time

some session-related activity takes place (such as creating a new

session, destroying a session, session switch, and so forth). Each

session is identified with a unique ID.

The call pertaining to the current topic is the Query_Suspend call

made by the switcher before switching away from an application (in the

case of Windows 3.1, even when switching away to an MS-DOS-based

application). The switcher calls the call-in function of each respondent

with the following parameters:

On Entry: AX = 1

          BX = current session ID

          ES:DI = call-in address of switcher

At this point, interrupts are enabled and MS-DOS calls can be made. The

application can fail this call by returning AX = 1 and can allow this

switch by returning AX = 0. If any respondent fails the call, the

switch is prevented. Global clients, such as network managers, can

take certain actions during this call to complete/suspend asynchronous

activity related to the session. If a safe switch is possible after

these actions, then they can allow the switch.

The respondent gets another chance to fail the switch even if all the

respondents return successfully from the Query_Suspend call. This is

the final opportunity for a respondent to fail the switch. The call-in

function of each respondent is called with the following parameters

(Suspend_Session call):

On Entry: AX = 2

          BX = current session ID

          ES:DI = call-in address of switcher

On Exit:  AX = 0 if switch can be performed safely, else 1

At this point, interrupts are disabled and MS-DOS calls may NOT be

made. If all respondents return with AX =0, the switch is performed.

The switcher also provides a way for a global respondent to maintain

per-session data, to test if some part of memory is local/global and

also to enable/disable the switcher.

In addition to the task switcher API defined in the MS-DOS

programmer's reference, another API has been implemented in Windows

3.1 for applications to obtain global memory (if available). This can

be used to maintain global data or interrupt handlers for applications

and allow a safe switch. For example, in Windows version 3.0, after an

asynchronous NetBIOS request, the user could not switch away from the

application that made the request; in Windows version 3.1, if global

memory is available, this switch can be made. To set global memory to

be reserved for all the applications, two switches are provided in the

SYSTEM.INI file. The global memory reserved by Windows is the sum of

NetHeapSize in the [standard] section and GlobalHeapSize in the

[NonWindowsApp] section. The default for GlobalHeapSize is zero. The

default for NetHeapSize is eight.

Users running a configuration with insufficient global memory can

encounter the error message "Switch has been prevented due to

asynchronous network activity" when an attempt is made to switch away

to an MS-DOS-based application from Windows, and when some asynchronous

activity has taken place from within Windows (for example, Terminal is

running).

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


Determining Free Memory in Windows Enhanced Mode

Article ID: Q74941

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

When an application requires memory for a particular purpose, it

should request that amount of memory from the system. If a given

request fails, the application can present an error message to the

user, or make a smaller request.

In the MS-DOS (non-Windows) environment, it is customary for an

application to request that the operating system determine how much

memory is free and report that information. The application can then

allocate that amount of memory and scale its capacity limits

accordingly. This is acceptable in an environment where only one

application is running at any given time, which has complete access to

all system resources available.

However, in the Windows cooperative multitasking environment,

applications must share system resources with other applications

running simultaneously.

MORE INFORMATION

================

In enhanced-mode Windows, determining the amount of free system memory

is a very complex problem because Windows uses virtual memory. There

are also a number of different types of memory that are used for

specific purposes. The following list enumerates some of these memory

options:

   DDE share

   Discardable

   Fixed

   Movable

   Page locked

   Pageable

   Provided by GlobalDOSAlloc

The presence of any of these attributes will affect the amount of free

memory.

It has been suggested that to attempt an allocation and then properly

handle failure by potentially trying another allocation is too slow.

However, it is doubtful that any method of calculating available

memory will be any faster (if such a calculation was even possible).

An overriding complication is that any memory use in another

application or in a virtual machine will invalidate any computed

value.

An excellent discussion about dealing with varying amounts of system

memory is in Chapter 18 of "Peter Norton's Windows 3 Power Programming

Techniques" (Bantam Books, 1990) beginning on page 661. Given the

caveats above, it is possible to obtain a very rough estimate of free

system memory. Two routines report this information: the GlobalCompact()

API and the MS-DOS Protected Mode Interface (DPMI) function 0500h (get free

memory information).

There are two pools of memory in enhanced-mode Windows:

1. The DPMI memory pool managed by the WIN386 paging memory manager.

   Use DPMI function 0500h to determine the size of this pool.

2. The global heap memory pool(s) managed by KRNL386.EXE (the Windows

   enhanced-mode Kernel. Use the GlobalCompact(-1) function to

   determine the size of this pool.

A rough estimate of available memory can be computed by placing the

following code fragment into an application:

  FreeMemEst = max(GlobalCompact(-1),

             (DPMI_Call_AX_0500h->MaxUnlockedPageAlloc - 1L) * 4096L);

  FreeMemEst = min(FreeMemEst, (16L * 1024L * 1024L) - (64L * 1024L));

The first line of code determines available memory according to both memory

managers. The second line accounts for the limitation imposed by the

GlobalAlloc() API, which sets the maximum size of a segment at (16

megabytes minus 64 kilobytes). The GlobalCompact() API does require a lot

of processing time, especially in standard (286 protect) mode.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Passing File Handles from TSR to Windows-Based App

Article ID: Q75257

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

MS-DOS file handles are associated with a PSP (program segment prefix).

For an MS-DOS terminate-and-stay-resident program (TSR) to open and

operate on files on behalf of a Windows-based application, or to share file

handles between MS-DOS TSRs and Windows-based applications, the TSR and

application must be operating with the same PSP. This is possible

because every Windows-based application has an MS-DOS PSP. Therefore, it is

simply a matter of ensuring that the Windows-based application's PSP is the

current PSP when the MS-DOS TSR opens or operates on a file. This

article discusses some of the details involved with this process.

MORE INFORMATION

================

The Windows Kernel creates a unique MS-DOS PSP for every Windows-based

application that is started. The only time that the application's PSP

must be selected as the current PSP is when the application calls

MS-DOS. Therefore, an application cannot assume that its PSP is the

current PSP. Listed below are two ways to have the PSP set so that a

TSR can open or operate on a file on the application's behalf:

1. The Windows-based application performs an MS-DOS call just prior to

   calling the TSR. This MS-DOS call must involve the file system; just

   retrieving the time of day is not enough. One good choice might be

   Get File Attributes (INT 21h, function 43h). Another possibility is

   to open a file. As long as the application does not yield [by

   calling the GetMessage, SendMessage, PeekMessage, and so

   forth functions], the Kernel will set the PSP for the MS-DOS call

   and will not change it. At this point, the application can call the

   TSR secure in the knowledge that the PSP is set correctly.

2. The TSR can set the current PSP using INT 21h, function 50h (the BX

   register is the segment of the new PSP). To do this, it is

   necessary that either the Windows-based application or the TSR determine

   the PSP for the application.

   The TSR can determine the correct PSP by following these three

   steps:

   a. Have the application perform an MS-DOS call just prior to the first

      call to the TSR.

   b. Determine the identity of the PSP by calling INT 21h, function

      51h (the segment of the current PSP is returned in the BX

      register).

   c. Save this information or return it to the application that will

      use the PSP as a parameter in subsequent calls to the TSR.

   The application can determine the PSP segment by following these

   three steps:

   a. Call the GetCurrentPDB function to determine its Program Data

      Base (PDB). The PDB is the Windows equivalent of the PSP.

   b. In protected mode, the value returned is a selector. The

      application must determine the segment address to which the

      selector maps by using the GetSelectorBase function.

      Note that the GetSelectorBase function is not documented in the

      Windows Software Development Kit (SDK); however, the function is

      documented in the Windows Device Development Kit (DDK). The

      function returns a LONG which is the linear address of the base.

      Dividing this value by 16 yields a segment value. Because PDBs

      are allocated using the GlobalDOSAlloc function, the linear

      address is always below 1 megabyte.

   c. Once the Windows-based application has determined its PSP, specify

      the PSP as a parameter when calling the TSR.

In Windows version 3.1, an installable driver mechanism has been

added that allows for essentially a Windows TSR. An installable driver

can be loaded at boot time or on demand by an application. It receives

notifications in real and standard mode when the user switches away from

or back to Windows to allow the driver to perform clean-up and/or

re-initialization operations as necessary. In all other respects, it is

a standard DLL.

Additional reference words: 3.00 3.l0

KBCategory: kbprg

KBSubcategory: KrIsrTsr


Determining Windows Version, Mode from MS-DOS App

Article ID: Q75338

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

The following assembly language code fragment can be used in an MS-DOS

(non-Windows) application to determine if it is running in a Windows

MS-DOS window, and if so, which version and mode of Windows is

running.

NOTE: Applications for Windows should use the GetWinFlags() function to

determine which version of Windows is running.

test_win proc near

; check for Windows 3.1

    mov     ax,160ah                ; WIN31CHECK

    int     2fh                     ; check if running under Win 3.1.

    or      ax,ax

    jz      RunningUnderWin31       ; can check if running in standard

                                    ; or enhanced mode

; check for Windows 3.0 enhanced mode

    mov     ax,1600h                ; WIN386CHECK

    int     2fh

    test    al,7fh

    jnz     RunningUnderWin30Enh    ; enhanced mode

; check for 3.0 WINOLDAP

    mov     ax,4680h                ; IS_WINOLDAP_ACTIVE

    int     2fh

    or      ax,ax                   ; running under 3.0 derivative?

    jnz     NotRunningUnderWin

; rule out MS-DOS 5.0 task switcher

    mov     ax,4b02h                ; detect switcher

    push    bx

    push    es

    push    di

    xor     bx,bx

    mov     di,bx

    mov     es,bx

    int     2fh

    pop     di

    pop     es

    pop     bx

    or      ax,ax

    jz      NotRunningUnderWin      ; MS-DOS 5.0 task switcher found

; check for standard mode Windows 3.0

    mov     ax,1605h                ; PMODE_START

    int     2fh

    cmp     cx,-1

    jz      RunningUnderWin30Std

; check for real mode Windows 3.0

    mov     ax,1606h                ; PMODE_STOP

    int     2fh                     ; in case someone is counting

    ; Real mode Windows 3.0 is running

    jmp     NotRunningUnderWin

RunningUnderWin30Std:

    ; Standard mode Windows 3.0 is running

    jmp     NotRunningUnderWin

RunningUnderWin31:

    ; At this point: CX == 3 means Windows 3.1 enhanced mode

    ;                CX == 2 means Windows 3.1 standard mode

    jmp     NotRunningUnderWin

RunningUnderWin30Enh:

    ; Enhanced mode Windows 3.0 is running

NotRunningUnderWin:

        ret

test_win endp

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


PRB: One Cause of Fatal Exit 0x0140 "Local Heap Is Busy"

Article ID: Q75359

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The debugging version of Windows reports Fatal Exit 0x0140.

CAUSE

=====

A module with no heap (such as a no-data dynamic-link library) uses

LocalAlloc to allocate local memory. Even if the application does not call

LocalAlloc directly, application startup code in the C run-time libraries

allocates memory to store the command-line arguments.

RESOLUTION

==========

Make sure that the proper library is specified on the LINK command line.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrDebug


Techniques to Find Extended Memory in a Windows DLL

Article ID: Q75682

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

For a Windows-based application to determine the amount of extended memory

installed in the machine on which it is running, the extended memory word

can be retrieved from the machine's AT Real Time Clock/CMOS RAM. Typically,

80286, 80386 SX, 80386 DX, and i486 based computers store setup information

in CMOS. This article details how to access this data.

MORE INFORMATION

================

The AT Real Time Clock/CMOS RAM is accessed via port 70h, and read from and

written to via port 71h. The extended memory word is stored low-order byte

first in the CMOS. The first (low order) byte is stored at address 17h, and

the second (high order) byte is stored at address 18h.

To read a particular address in the CMOS, write the address to read to port

70h, then retrieve the information from port 71h. Figure 1 contains a code

fragment, written in Microsoft C version 6.0 with inline assembly, which

shows how to check the CMOS for extended memory size. For compatibility

with future versions of Windows, the following code should NOT be placed

directly into a Windows-based application. Instead, this code should be

placed in a dynamic-link library (DLL), which can be called by

applications.

Figure 1. Sample Extended Memory Size Check

-------------------------------------------

   int MemorySize = 0;

    _asm

        {

        xor   ax, ax

        mov   al, 17h

        out   70h, al

        ; jmp   $+3               ; delay not needed in most cases

        in    al, 71h

        mov   MemorySize, ax

        mov   al, 18h

        out   70h, al

        ; jmp   $+3               ; delay not needed in most cases

        in    al, 71h

        xchg  al, ah

        or    MemorySize, ax

        }

     printf("\nExtended Memory size = %u KB\n", MemorySize);

The AT Real Time Clock/CMOS RAM configuration is documented in its entirety

in the IBM PC technical reference, on pages 1-56 to 1-68. The information

contained in the article was obtained from "The Programmer's PC Source

Book," by Thom Hogan, published by Microsoft Press (1988).

Please note that although the BIOS on most machines automatically

configures the CMOS entry for extended memory size with the amount of

memory the BIOS power-on self-test (POST) routines find in the machine,

some BIOS setup programs allow the user to configure the extended memory

setting themselves. If the user has not filled in the correct number for

the amount of extended memory installed in the machine, the check described

in this article will be useless.

WEXTMEM is a file in the Software Library that contains source code for a

Windows-based application that reports the amount of extended memory

installed in the machine on which the program is run.

Download WEXTMEM.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WEXTMEM.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WEXTMEM.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WEXTMEM.EXE

Additional reference words: 3.00 3.10 softlib

KBCategory: kbprg kbfile

KBSubcategory: KrMm


PRB: One Cause of Fatal Exit 0x001A

Article ID: Q75737

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Closing an application or dynamic-link library (DLL) causes Windows to

issue the undocumented fatal exit 0x001A.

CAUSE

=====

The application or DLL has registered a window class with the

CS_GLOBALCLASS style. The fatal exit is issued when Windows terminates the

application or DLL that registered the class, when a window of that class

is still open.

RESOLUTION

==========

Ensure that all windows of any classes registered by an application or DLL

are closed before the application or DLL is terminated.

MORE INFORMATION

================

Applications and DLLs can register window classes that are visible to all

applications by using the class style CS_GLOBALCLASS. This style is most

commonly used in custom-control DLLs that are meant to be shared by

multiple applications.

When a task (that is, an application) terminates, all classes registered by

that application are unregistered. In addition, DLLs that were implicitly

loaded by the terminating application are freed if only the terminating

application is using the DLL. In a similar fashion, during the unload

sequence of a DLL, any classes that it registered are also unregistered.

Windows keeps an internal count of windows created with a specific class.

If this count is not zero when a class is unregistered, Windows reports

fatal exit 0x001A.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrDebug


Determining What Mode and Version of Windows Is Running

Article ID: Q75943

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

An MS-DOS (non-Windows) application can determine whether it is

running within an MS-DOS session under Windows. This article provides

an assembly language program that demonstrates how this can be

accomplished.

For information on determining if Windows is running in enhance mode please

see the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q75338

   TITLE     : Determining Windows Version, Mode from MS-DOS App

The following code determines whether Windows is running; if Windows

is running, the code determines what mode Windows is in and what

version of Windows is running.

Sample Code

-----------

.MODEL LARGE

.CODE

             public  _iswin

;

;       Procedure to determine if in Windows or not.

;               (From "Microsoft Systems Journal," March 1991, page 113)

;               0:      Windows not running

;               1:      Windows/386 2.x is running

;               3:      Windows 3.x is in 386 enhanced mode

;               4:      Windows 4.x is in 386 enhanced mode

;             127:      Windows/386 2.x is running

;             128:      Windows 3.0 is in real mode

;             255:      Windows 3.0 is in standard mode

;

_iswin       PROC    FAR

             MOV     AX,4680H        ;Is Windows 3.0 running?

             INT     2FH

             XOR     AL,80H

             MOV     CL,AL

             MOV     AX,1600H        ;Is Windows 3.x 386 enhanced mode

             INT     2FH             ;running?

             AND     AL,7FH

             OR      AL,CL

             CMP     AL,80H

             JZ      T1              ;Not Windows enhanced mode.

            ; Windows enhanced mode is running. At this point,

            ; AL contains the major version number of Windows

            ; and AH contains the minor version number.

            ; However, for this example, only the major version

            ; number is used.

             JMP     GOHOME          ;Windows Enhanced, Go Home

T1:          MOV     AX,1605H        ;Simulate Initialization.

             XOR     BX,BX

             MOV     ES,BX

             XOR     SI,SI

             MOV     DS,SI

             XOR     CX,CX

             MOV     DX,0001H        ;MS-DOS extender

             INT     2FH             ;Windows real or Windows standard

             CMP     CX,+00

             JNZ     T2

             MOV     AX,1606H        ;Simulate exit

             INT     2FH

T2:          MOV     AL,80H

             OR      AL,CL

GOHOME:

             MOV     AH,4CH

             INT     21H

_iswin       ENDP

             END

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


Using TOOLHELP to Determine Free System Resources

Article ID: Q76247

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

In Windows version 3.1, a Windows-based application can obtain the amount

of free system resources in two ways:

1. By calling the GetFreeSystemResources() function, which is exported

   by KERNEL

2. By calling the SystemHeapInfo() function, which is exported by the

   TOOLHELP.DLL dynamic-link library

Under Windows 3.0, the GetFreeSystemResources() function is not available.

If TOOLHELP.DLL is present, a Windows 3.0 application can use

SystemHeapInfo(). If TOOLHELP.DLL is not present, there is no supported

method for a Windows 3.0 application to obtain the amount of free system

resources.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrToolHlp


Determining Which COM Ports Are Present in Enhanced Mode

Article ID: Q76280

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

A problem with the communications driver causes a device contention

message box to appear when a nonexistent port is opened in enhanced

mode Windows using the OpenComm function. This article describes a

method of avoiding this message box when using the communication API

under enhanced mode Windows.

ENUMPORT.EXE is a file in the Software/Data Library that demonstrates

the techniques detailed in this article.

Download ENUMPORT.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for ENUMPORT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ENUMPORT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ENUMPORT.EXE

MORE INFORMATION

================

Under standard or real mode, the OpenComm function can be used to

successfully test for the presence of communications hardware by

checking the return value. If the return value of the OpenComm

function is IE_HARDWARE, it is safe to assume that the hardware is not

present.

However, under enhanced mode Windows, calling the OpenComm function

with a port ID that is not valid will cause the following message to

appear on the screen:

   The COMx port is currently assigned to an MS-DOS-based application. Do

   you want to reassign the port to Windows?

This message is also be displayed if the port ID is valid; however, it

is in use by another virtual machine.

To avoid this message in enhanced mode Windows, a communications

application can call the API entry point of the virtual communications

device (VCD) with a special function ID to determine the valid ports

in the system.

The code fragment included below will fill a byte with a value that

enumerates the valid COM ports:

VCD_Device_ID   equ     0Eh

lpAPI           dd      ?

bPortArray      db      ?

EnumeratePorts:

                xor     di, di

                mov     es, di

                mov     ax, 1684h

                mov     bx, VCD_Device_ID

                int     2Fh

                mov     ax, es

                or      ax, di

                jz      Enumerate_Failed

                ; VCD API is available... enumerate the ports

                mov     word ptr lpAPI, di

                mov     word ptr lpAPI+2, es

                mov     dx, 1           ; API for Get_Port_Array

                call    dword ptr lpAPI

                mov     bPortArray, al  ; returned in AL

                jmp     Enumerate_Exit

Enumerate_Failed:

                mov     bPortArray, 0

Enumerate_Exit:

                ret

After running this code fragment, the value in bPortArray will

determine the valid ports. For example:

        bit 0   - COM1 (set if COM1 is available)

        bit 1   - COM2 (set if COM2 is available)

        ...

        bit 8   - COM7 (set if COM7 is available, not supported in

                        standard VCD)

A value of 3 indicates that both COM1 and COM2 are present in the

system.

Additional reference words: 3.00 3.10 softlib ENUMPORT.ZIP

KBCategory: kbprg kbfile kbcode

KBSubcategory: KrCommapi


Full-Screen MS-DOS Apps Slow Timer Msgs in Enhanced Mode

Article ID: Q76390

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In 386 enhanced mode, Windows system timer (WM_TIMER) messages are

generated less often when an MS-DOS-based application runs full-screen with

its PIF file specifying background execution than when the same

MS-DOS-based application runs in a window.

When a full-screen MS-DOS-based application is running, Windows does not

need to track the mouse and update the screen. Therefore, Windows runs with

a low priority in the background. Windows-based applications receive fewer

WM_TIMER messages because the number of timer ticks that Windows

receives decreases from 18.2 per second to 2 per second or even fewer.

MORE INFORMATION

================

Windows's 386 enhanced mode architecture and display mechanism account

for the way that WM_TIMER messages behave when MS-DOS-based applications

are running.

First of all, WM_TIMER messages are not guaranteed to be sent exactly

at a specified time; they may be sent any time after the specified

time has elapsed. For example, a WM_TIMER message set for 60

milliseconds may be sent at exactly 60 milliseconds, or it may be sent

more than two minutes later. WM_TIMER messages behave this way because

they have the lowest priority of any Windows message. Applications

receive WM_TIMER messages only after all other messages in the system

have been processed (that is, when all message queues are empty).

In 386 enhanced mode, Windows uses a virtual machine architecture that

sets up a virtual machine (VM) for each MS-DOS-based application. Windows

is essentially an MS-DOS-based application and creates a VM for itself

called the System VM. The System VM runs Windows and all Windows-based

applications; each MS-DOS-based application receives a separate VM.

Virtual machines behave like 8086 processors with additional privileged

instructions provided by the 80386 processor's virtual-8086 mode. Virtual-

8086 mode differs from real mode in that it has memory protection, virtual

memory, and privilege-checking mechanisms. Each virtual machine also has an

optional protected-mode portion. The System VM uses its protected mode

portion to run Windows-based applications.

The Windows Virtual Machine Manager (VMM) controls the multitasking of

the virtual machines; it manages memory, CPU execution time, and

device coordination. The VMM runs in the 80386 processor's 32-bit flat

memory model along with Windows virtual devices (VxDs), and

preemptively schedules the virtual machines.

Foreground virtual machines running MS-DOS-based applications always

receive 18.2 timer ticks each second so that the VM looks exactly like a

stand-alone 8086 machine. When the System VM is in the foreground, it

(and Windows) receives 18.2 timer ticks per second as well.

Background virtual machines do not receive 18.2 timer ticks per

second; they receive 2 or fewer ticks per second because the VMM

reduces their relative priorities. As a result, the foreground VM can

run faster.

When the System VM is in the background and a full-screen MS-DOS-based

application is in the foreground, Windows receives fewer timer ticks,

and therefore runs slower than normal. Windows-based applications process

their messages slower, causing WM_TIMER messages to be delayed.

Windowed MS-DOS-based applications behave differently from full-screen

MS-DOS-based applications. Windows creates a special agent application,

WINOLDAP, to run windowed MS-DOS-based applications. WINOLDAP's job is to

place all output from an MS-DOS-based application into the client area of a

window. Windows controls all parts of the display, including the area of

the windowed MS-DOS-based application, and tracks the mouse pointer.

Under such circumstances, Windows is running in the background with a

high priority. The windowed MS-DOS-based application is running in the

foreground in a VM. The VMM preemptively multitasks the VMs so that

the MS-DOS-based application can run and Windows can manage the screen.

Because the System VM has a high priority, it receives more timer ticks per

second than other background VMs. Windows and Windows-based applications,

therefore, process more messages, which allows WM_TIMER messages to be

sent more often.

Even though background VMs receive fewer timer ticks per second, they

still receive time slices according to their relative priorities.

NOTE: This article applies to MS-DOS-based applications that have a PIF

file set for background execution. If the MS-DOS-based application is

running full-screen in the foreground with its PIF file set to exclusive

processing, all other applications, including Windows, will be

suspended, just as if the MS-DOS-based application were run under Windows

in standard mode. If the MS-DOS-based application runs in a window with

exclusive processing set, then Windows does not get suspended because it

must manage the screen output for the MS-DOS-based application.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


PRB: Global TSR Pop-ups Incompatible with Windows

Article ID: Q76452

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

If a TSR (terminate-and-stay-resident) program loaded before Windows (a

global TSR) is used to create a pop-up window over the Windows display, the

display will be disrupted.

CAUSE

=====

When a global TSR pop-up window attempts to overlay the Windows display,

the pop-up places the system virtual machine into text mode, which disrupts

the Windows Virtual Display Device (VDD). When the pop-up is complete, the

display is not restored properly.

RESOLUTION

==========

Global TSR pop-ups are incompatible with Windows. The same functionality

should be written into a Windows-based application.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrIsrTsr


General Information Regarding Dynamic-Link Libraries

Article ID: Q76476

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Dynamic-link libraries (DLLs) are very useful tools in Windows programming.

Many applications can use the code in a DLL, meaning that only one copy of

the code is resident in the system. It is possible to update a DLL without

changing applications that use the DLL, as long as the interface to the

functions in the DLL does not change.

This article provides some general information regarding DLLs.

MORE INFORMATION

================

The small and medium memory models are the preferred memory models for

Windows 3.0 applications and DLLs. By default, the compact and large

memory models create multiple data segments. These data segments are

fixed in the memory space and cause difficulties for all applications

running in Windows. Fixed segments in standard and enhanced modes can

cause fragmentation of the heap. Because of a problem in Windows 3.0,

all fixed segments are also page-locked, and can overburden the

enhanced-mode virtual memory manager.

In Windows 3.1 with the Microsoft C/C++ and later compilers, the large

model is the preferred method since the problem with Windows 3.0 has been

fixed in Windows 3.1.

If an application requires the large memory model, a method can be

used to unpage-lock the extra data segments of the DLL. For additional

information on large-model programming, query on the following words in

this Knowledge Base:

   large and model and protected

However, if the language compiler used supports the large memory model

with a single data segment, this method is not required.

When compiling a DLL with the Microsoft C Compiler, specify the -Aw

switch so that the code generator does not assume that the

application's stack segment is equal to its data segment (SS != DS).

The generated code will not automatically load DS at each module entry

point. The -An switch should be used to specify near data, and the -As

or -Al switch to specify near or far code, respectively.

When writing code in DLLs, it is important to remember that SS != DS.

This is an issue when an application function passes a pointer to one

of its local variables to the DLL function. In Microsoft C, all near

pointers are assumed to be relative to DS. The way to avoid problems

is to either:

 - Use a function prototype declaring the parameter to be a FAR

   pointer.

 - Explicitly cast the parameter to FAR.

When using Microsoft C run-time functions, specify the model

independent functions; for example: _fmemcpy, _fmemset.

The -Gw compiler switch generates the Windows prolog and epilog code.

When a function is called, the prolog saves the current data segment

on the stack. When memory moves in real mode, Windows "walks" the

stack and changes the stored DS values to reflect the memory motion.

The prolog code is not required when a DLL will be used only in

protected mode. There are two restrictions when choosing not to use

the -Gw switch in protected mode:

1. Windows debuggers will not be able to properly provide stack trace

   information.

2. Exported functions must include the _loadds attribute in the

   declaration of the function. The following is an example

   declaration:

      BOOL FAR PASCAL _loadds ExportedFunction(VOID)

DLL functions that will be called from applications should be declared

with the FAR modifier because an intersegment jump is required from

the application. Functions that are only called from within the DLL

may be declared NEAR. The PASCAL or _cdecl calling conventions may be

used as appropriate. Functions called from Windows must be declared

using the PASCAL calling convention.

When exporting _cdecl functions in the module definition (DEF) file,

one must maintain the case of the function name and use an underscore

prefix. For example:

EXPORTS

   WEP                  @1  RESIDENTNAME

   _ExportedFunction    @2

A DLL is limited to one instance. The DATA SINGLE or DATA NONE

statements can be used in the DEF file to specify that the DLL should

have a data segment of its own or not. Because a DLL does not have a

stack of its own, automatic variables are allocated from the stack of

the calling application.

DLLs can maintain data by using the local or global memory allocation

routines. In most cases, memory allocated by GlobalAlloc is owned by

the calling task. Global memory allocated by DLLs with GMEM_DDESHARE

specified is owned by the DLL. When using local memory management

functions, allocations are performed within the current data segment.

Therefore, the handles returned from these calls are only valid when

processed by the DLL.

Naming the segments within the DLL, keeping segment size less than 16K

and specifying the segment options PRELOAD, LOADONCALL, MOVEABLE, and

DISCARDABLE, as appropriate, will ease memory requirements and

simplify the task of the memory manager.

There are three methods to access the functions in the DLL:

1. List the names of the functions in the IMPORTS section in the

   application's DEF file.

2. Link the application to an import library generated from the DLL's

   DEF file using the IMPLIB utility.

3. Use the LoadLibrary and GetProcAddress functions to load the

   library and retrieve a pointer to the function, respectively. This

   dynamic-dynamic linking method is the most powerful.

These methods are documented in Section 20.4.2 of the "Microsoft

Windows Guide to Programming," pages 20-31 through 20-34.

For additional information regarding linking DLL routines, please see page

178 of the Microsoft Visual C++ "C Language Reference".

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


PRB: LoadLibrary() Returns Error 6

Article ID: Q76581

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the LoadLibrary() function is used to load a dynamic-link library

(DLL), the handle returned has the value 6.

CAUSE

=====

The library's module definition (DEF) file declares DATA MULTIPLE.

RESOLUTION

==========

Modify the DEF file to declare DATA SINGLE.

MORE INFORMATION

================

A DLL has only one data segment regardless of the number of applications

that use the DLL. For more information, see pages 20-26 and 20-27 of the

Microsoft Windows SDK "Guide to Programming" for version 3.0, and pages

481-482 of the Microsoft Windows SDK version 3.1 "Guide to Programming."

Additional information may also be found by querying on the words in the

Microsoft Knowledge Base:

   prod(winsdk) and KrDll

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrDll


PRB: Reset A20 Bit Set During DPMI Simulate Interrupt Crash

Article ID: Q76582

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

A Windows-based application that specifies "reset interrupt controller and

A20 line" when calling the MS-DOS protected mode interrupt (DPMI) function

"Simulate Real Mode Interrupt" can cause Windows to crash.

RESOLUTION

==========

Applications that use the "Simulate Real Mode Interrupt" function must

ensure that this bit is not set.

MORE INFORMATION

================

The "Simulate Real Mode Interrupt" function is documented in the DPMI

specification.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrDpmi


Differences Between Task Handles and Instance Handles

Article ID: Q76676

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows creates two handles associated with each task running in the

system. One handle is the instance handle, hInstance, which is passed to

the WinMain function when the program starts execution. The other handle is

the task handle, hTask, which is returned by GetCurrentTask().

MORE INFORMATION

================

The numerical values of hInstance and hTask are different. In some

routines, hTask can be used in place of hInstance without any problems. In

other routines, using hTask in place of hInstance causes incorrect behavior

and may result in unrecoverable application errors (UAEs). Using hTask in

place of hInstance is considered bad form and will probably cause problems

when the application is run under future versions of Windows.

To retrieve the instance handle for the application currently running,

use the following code fragment:

   hInstance = GetWindowWord(GetActiveWindow(), GWW_HINSTANCE);

To retrieve the task handle for the application currently running, use

the following code fragment:

   hTask = GetCurrentTask();

The instance handle, hInstance, is used to identify the data

associated with a particular instance of an application. The task

handle, hTask, is the handle to a structure, called the task database

(TDB), which contains information about the task (for example, its

queue, module handle, and so forth). The instance handle and the PDB

(program database), also known as the PSP (program segment prefix),

are also stored in the task database. The GetCurrentPDB() function

returns a handle to the current PDB.

Each instance of an application has both an instance handle and a task

handle. Dynamic-link libraries (DLLs) are not tasks; therefore, they

have only an instance handle and do not have a task handle.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


Properly Using Dynamic-Link Libraries

Article ID: Q76682

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Many application developers try to use a dynamic-link library (DLL) as

a second application. However, DLLs are designed to provide resources

to applications.

Two problems typically arise with the use of DLLs:

1. A DLL opens a file and leaves it open.

2. The DLL improperly allocates memory.

This article addresses these two issues.

MORE INFORMATION

================

When a DLL opens a file, the file handle is stored in the task

database (TDB). The TDB is similar to, but not the same as the program

segment prefix (PSP) used by applications that are not based on Windows.

Because the DLL does not have a TDB, the handle is stored in the TDB of the

application that called the DLL.

If the file is left open when the application terminates, the handle

is freed and becomes invalid. A future attempt to use the handle

results in an attempt to access an invalid file handle.

Files should be opened, read from or written to, and closed as quickly

as possible within the application.

When a DLL allocates global memory, the handle is stored in the TDB of the

calling application. For similar reasons to the file case, if a DLL

allocates global memory and the application that caused the allocation

terminates, the global memory block is freed. An attempt to use the memory

block will result in a general protection violation, usually reported as an

unrecoverable application error (UAE).

To avoid this problem, global memory allocations from a DLL should specify

the GMEM_DDESHARE flag. When this flag is specified, the allocated

memory is bound to the DLL code segment, not an application. Because

the DLL owns the memory, when the application that caused the

allocation terminates, the memory remains valid.

When the DLL terminates, the memory block is freed.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Memory Access Methods for Protected Mode Applications

Article ID: Q77226

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Applications that will run solely in one of Windows protected modes

(standard mode or enhanced mode) can take advantage of the attributes

of protected mode to reduce the size and improve the speed of the

application.

These techniques do not apply to applications that can be run in Windows

real mode.

MORE INFORMATION

================

To assure compatibility with future versions of Windows, an application

should not make any assumptions about the protection ring of memory

selectors the system provides for memory allocations.

Using global memory can be more straightforward when an application is

developed for the protected-mode environment. The following four steps

provide a procedure for using memory:

1. Use the GlobalAlloc() function to allocate memory. Applications

   should ALWAYS use the GMEM_MOVEABLE attribute, which signifies that

   the linear address of the memory block can be changed by the

   system. The selector or handle to this block will not change unless

   the application calls GlobalRealloc() to modify the handle, and

   changes the number of 64K blocks required to satisfy the request.

   For example, the selector can change if a 60K block is increased to

   70K or if a 70K block is reduced to 60K.

2. Use the GlobalLock() function to obtain the corresponding selector.

   In protected mode, there is no need to bracket each use of an

   object with GlobalLock/GlobalUnlock calls. These calls are required

   in real mode because the Windows memory management algorithm cannot

   move locked objects in memory. In protected mode, locked objects can

   be moved without changing the selector value that is used to refer

   to the object.

3. Use the selector and the range of offsets (from zero to the size of

   the block) to access the memory.

4. When the memory block is no longer required, unlock the memory

   block using the GlobalUnlock() function, and free the selector using

   the GlobalFree() function.

Some applications introduce incompatibilities by implementing a

private version of the GlobalLock() function to translate a handle to

a selector. While a private function can be made to work for any one

version of Windows, it is not guaranteed to work in future versions.

The four steps above may be used for discardable memory. However,

Windows cannot discard the memory while it is locked. Therefore, even

in protected mode, applications that use discardable memory objects

should unlock each object when it is not in use. This makes these

memory blocks candidates for discarding should the system run out of

memory.

Selectors should not be shared between applications unless the rules

outlined in the dynamic data exchange (DDE) specification are

followed. In particular, the GMEM_DDESHARE or GMEM_SHARE flag must be

specified in memory allocation requests. Future versions of Windows

may implement separate address spaces; any applications that

improperly share memory will not function properly in any such

release.

An application that uses any of these techniques should specify the

Resource Compiler -T switch when resources are added to the

application. This will prevent the application from running in real

mode.

Additional techniques to decrease the size and increase the speed of

an application developed for protected mode can be found by searching

on the words in this Knowledge Base:

   streamlined

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Considerations for Programming DATA NONE DLLs

Article ID: Q77365

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Windows Software Development Kit (SDK) documentation regarding

dynamic-link libraries (DLLs) is not very detailed with regard to some

facets of developing DLLs. In this article, some of the lesser known

considerations for developing DLLs are discussed.

MORE INFORMATION

================

The primary reason for using a DATA NONE DLL is to ensure that the data

segment (DS) is equal to the stack segment (SS). Many of the functions

provided with the Microsoft C run-time libraries expect that DS == SS.

Functions with this property have been removed from the Windows SDK DLL

libraries. In DATA SINGLE DLLs, the DLL will use the application's SS, but

the DLL will have its own DS. DS is then not equal to SS and the C run-time

functions (or other functions expecting DS == SS) may not be used. In DATA

NONE DLLs, however, the DLL uses the application's DS and SS. In

applications, DS == SS; therefore, for a DATA NONE DLL, DS == SS.

While this may sound like a straightforward process, there are some

items declared within a DLL that can create a data segment. Windows

looks at a flag to determine if the DLL has a data segment. If DATA

NONE has been declared, Windows will treat that DLL as a DATA NONE DLL

whether a data segment exists or not. However, the Windows loader uses

information from the linker to determine what segments to load, not

how the flags are set. Therefore, data segments that do exist are

loaded into memory.

When additional data segments are created, because the compiler works

under the assumption that DS == SS, the data segments that are loaded

are not used and waste memory.

When a DATA NONE DLL does have a data segment, Windows will use the

application's DS as it should, but the offset into the data segment is

the offset into the DLL's data segment. Writing to any variable

declared in the DLL will overwrite data in the application's data

segment.

This type of bug is often difficult to track down. When the data

segment is built for the DLL, items are placed in the data segment

from bottom to top. So an integer variable will take up 2 bytes on the

bottom of the DLL's data segment. Writing to this variable will

overwrite 2 bytes at the bottom of the calling application's data

segment. An application's data segment normally contains thousands of

bytes; therefore, this type of error may go unnoticed and will not

cause a GP-fault.

Global variables, static variables, and static text (string literals

such as "Hello") declared in the DLL will create new data segments for

the DATA NONE DLL.

The warning message "RC: Warning RW4002: Non-discardable Segment 2 set

to PRELOAD" is quite common when DLLs are processed by the Resource

Compiler. However, it is not immediately obvious from the text of the

message why this is a problem. This warning is generated when a data

segment has been created but flags have not been defined for that

segment (such as NONE, PRELOAD, or SINGLE). The default setting for

these segments is PRELOAD SINGLE.

After ruling out all the obvious ways that a new data segment can be

created, it is time to look deeper into the heart of the code.

If the DLL uses the Microsoft C run-time code, a global internal

variable is used by the library. This variable is referenced in

LIBENTRY.ASM by the following code:

   extern __acrtused:abs

The __acrtused variable informs the linker that the C run-time code will be

used in the DLL. If the C run-time code is not used in the DLL, this

variable may be removed to create a true DATA NONE DLL. This is done by

replacing the C run-time libraries (SDLLCEW, MDLLCEW, and LDLLCEW) with the

appropriate libraries without the C run-time code (SNOCRTD, MNOCRTD, and

LNOCRTD, respectively). Along with these libraries, the /NOE option must

also be used. For more information on eliminating the C Run-time startup

code, refer to Section 14.5.10.1 in the "Guide to Programming" manual of

the Windows Software Development Kit version 3.1.

If the C run-time is used by the DLL, this variable must be declared

and using the DATA SINGLE declaration is encouraged. Declaring

__acrtused creates a data segment. However, the warning that occurs

when this is done in a DATA NONE DLL may often be ignored.

DATA SINGLE is also encouraged when the DLL contains literal strings.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Rules for Using Far Pointers to Memory Objects

Article ID: Q77473

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In Windows version 3.0 standard and enhanced modes, rules for using

far pointers have been relaxed substantially. This is due to the use

of the protected mode of the 80286, 80386, and 80486 processors. In

this mode, far pointers are no longer a segment:offset value.

Protected mode far pointers are made up of a selector:offset value.

The selector is an index into a descriptor table. Each descriptor

contains information about a block of memory, such as size, location

in memory (linear memory if in enhanced mode, physical memory if in

standard mode), and access rights. For more information on the

descriptor table, refer to Chapter 3 of "The 80386/80486 Programming

Guide" by Ross P. Nelson (Microsoft Press).

The protected mode of the 80286, 80386, and 80486 processors allows

memory blocks to be moved in memory without invalidating their

selector:offset value. This is accomplished by changing the reference

to the location in memory in the descriptor rather than changing the

actual selector value.

Because of this functionality, using far pointers in standard and

enhanced modes is much easier. In the following four circumstances,

far pointers to data can be assumed to be valid:

1. Global memory that is allocated with GlobalAlloc() as movable and

   nondiscardable

   The far pointer returned from GlobalLock() can be assumed to be valid

   as long as the GlobalUnlock() function has not been called. Once

   GlobalUnlock() has been called, the far pointer can no longer be

   assumed to be valid because the memory may be discarded. However,

   the far pointer will remain valid in the case of memory that is

   nondiscardable and is not an automatic data segment. Because of the

   selector technology discussed above, movable memory can move

   without invalidating the far pointer.

   NOTE: If a block is reallocated using GlobalReAlloc() and the new

   size requires a different number of selectors (for example 50K

   reallocated to 110K or 65K reallocated to 63K), the base selector

   value may be changed. Each selector can refer to a maximum of 64K

   of memory.

2. Far pointers to static or global data within an application

   Static and global data within an application is stored in the

   static data area of the application's DGROUP. Because the whole

   DGROUP segment is moved, the far pointer will still be valid after

   a move in protected mode.

3. Automatic data within a function as long as that function has not

   been exited

   Far pointers to automatic data will be valid as long as no return

   has been executed from the function that allocated the data.

   Automatic data is stored on the stack. When an application returns

   from a function, the memory allocated by that function is no longer

   allocated and cannot be assumed to be valid. This then makes memory

   that a far pointer references subject to corruption.

4. Local memory that has been locked with LocalLock()

   Memory allocated with LocalAlloc() comes from the local heap. Memory

   on the local heap can be moved around within the DGROUP segment,

   which will cause the offset value of its location to change. This

   will invalidate any far pointers to the memory. The LocalLock()

   function fixes the memory within the local heap.

For compatibility with future versions of Windows, far pointers to

data within an application should NEVER be passed to other

applications. The current version of Windows uses one LDT (local

descriptor table) for all descriptors associated with data. In the

future, one LDT may be used for each application's data, while a GDT

(global descriptor table) may be used for shared data. If a

selector:offset combination from one application is used in another

application in such an environment, the selector will be used to

reference a descriptor in the called application's LDT. The descriptor

in the called application's LDT will most likely not contain the

correct reference for the memory block. The only supported way to

share data between applications is global memory allocated with the

GMEM_SHARE (also known as the GMEM_DDESHARE) flag.

Selectors that are aliased, using AllocDStoCSAlias() or AllocSelector(),

will not be updated when the memory is moved. For this reason, far

pointers that include aliased selectors cannot be assumed to be valid

unless the memory has been fixed into place with GlobalFix().

For a more detailed description of memory management under protected

mode and Windows 3.0, see Chapters 17 and 18 of "Peter Norton's

Windows 3.0 Power Programming Techniques." This book is available from

Bantam Computer Books and is coauthored by Paul Yao.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Using _export Keyword or DEF File EXPORTS Statement

Article ID: Q77986

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In Windows 3.0 and later, the _export keyword should not be used as a

general replacement for exporting functions in the EXPORTS section of a

module-definition (DEF) file.

MORE INFORMATION

================

The _export declarator can sometimes be used to export functions from

Windows-based applications and dynamic-link libraries (DLLs); however, this

method has several limitations.

In the Windows environment, all callback functions must be flagged as

exported to ensure that the prolog code is fixed up at load time. The fixed

up prolog code works with the procedure-instance addresses returned from

the MakeProcInstance() function to bind the proper data segment to the

exported function when it is called.

Examples of callback functions are: window procedures, dialog box

procedures, and enumeration callback procedures (see Section 14.4, "Writing

Exported Functions" in the "Microsoft Windows Software Development Kit

Guide to Programming"). A DLL must also flag as exported any functions

called from other modules.

The second edition of "Programming Windows" by Charles Petzold (Microsoft

Press) has a good explanation of the special Windows prolog code and the

effects of listing functions in the EXPORTS section of the module-

definition file (pages 280-286 and 895-896).

Usually, functions are flagged as exported by listing them in the EXPORTS

section of the modules' module-definition file. In addition to enabling

fixup of the prolog code, exporting functions from the module-definition

file provides control of the ordinal values of the exported functions. This

is especially important for DLLs because existing applications that call

the exported functions will not need to be relinked when the DLL is

modified if the interface-function prototypes and ordinal values are not

changed between versions. Specifying ordinal values also allows the Windows

dynamic-link mechanism to operate faster and to use less memory.

When compiling Windows-based applications and DLLs using Microsoft C

version 6.0 and later, the _export keyword may be used in place of listing

the function in the EXPORTS section of the module-definition file, with the

following limitations:

 - This method provides no control over the ordinal values of the

   exported functions (as discussed above).

 - The function name is not resident. RESIDENTNAME, required for WEPs

   (Windows exit procedures) in DLLs, can be specified only in a

   module-definition file.

 - Exportname cannot be specified (no alias name).

 - The NODATA option cannot be specified.

 - The "parameter-option specification" cannot be overridden.

For more information, see pages 10-4 and 10-5 in the "Microsoft Windows

Software Development Kit Reference Volume 2."

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Real Mode Not Supported by Windows 3.1

Article ID: Q78326

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Support for real mode has been removed from Windows 3.1. Many applications

designed for Windows 3.0 do not support real mode. The reasons behind this

trend toward protected mode include superior memory management and smaller,

faster application code.

MORE INFORMATION

================

The remainder of this article lists the advantages and disadvantages of

removing support for real mode from applications.

Advantages of Removing Real Mode Support

----------------------------------------

1. Protected mode code is smaller, cleaner, and more maintainable.

   These factors lead to a faster, more responsive, more reliable,

   system. Code is smaller and cleaner for the following reasons:

   a. The 286 and higher processors can track memory locations in

      hardware, which makes locking and unlocking memory objects

      unnecessary. An object can be locked once when it is allocated

      and unlocked just prior to being freed. Because the object can

      move in memory even when it is locked, it is not necessary to

      bracket each access to an object with lock and unlock calls.

   b. Far functions can use simplified function prolog and epilog

      code. For more information on this aspect of protected mode,

      query on the following words:

         prod(winsdk) and protected and streamlined

   c. Because protected mode code is restricted to running on 286 and

      higher processors, the Microsoft C Compiler -G2 switch can be

      used to generate smaller and faster application code.

2. Protected mode (both standard and enhanced mode) breaks the "640K

   barrier." Furthermore, under enhanced mode, Windows uses paged

   virtual memory to expand available memory by using the system hard

   disk as a swapping device. The large address space allows

   applications to have more code and data and allows users to run

   more applications.

3. Testing is easier because there are fewer Windows modes to test. To

   fully test a product that runs under real mode, five separate modes

   must be tested. Real mode itself contributes three of those modes:

   real mode with no expanded memory, real mode using the small-frame

   Expanded Memory Specification (EMS) and real mode using the large-

   frame EMS. The other two modes are standard mode and enhanced mode.

   Because support for real mode has been eliminated, the same amount

   of testing effort can concentrate on producing a better product. It

   also provides an opportunity to develop and test additional

   enhancements. For more information on EMS, query on the following

   words:

      prod(winsdk) and ems and developers

4. Based on a survey of Windows developers, most developers are

   targeting only protected mode because Windows performance on 8086-

   based and 8088-based machines is not satisfactory. Furthermore,

   these machines cannot address more than 640K of RAM.

5. "Wild writes," write-accesses to memory that incorrectly modify a

   memory location, can frequently be detected in protected mode

   through the mechanism of a GP-fault (an unrecoverable application

   error). It is not possible to detect these errors under real mode.

   These GP-faults provide information about application bugs before

   the application is released.

For the reasons mentioned above, Microsoft is removing support for real

mode from Windows 3.1. For these same reasons, many developers have also

removed support for real mode from applications developed for Windows 3.0.

Applications that are written to support only protected mode should be

marked with the Resource Compiler's -T switch to prevent the application

from loading in real mode.

Removing support for real mode also benefits the end user because

applications run faster and are more reliable. While small applications run

quickly in real mode, larger applications run slowly. However, in protected

mode, large applications also run quickly. A collection of large and small

applications can be run simultaneously without any loss in speed. For

example, when more applications are running simultaneously than can fit in

the physical memory installed in the system, the paging mechanism (only

available in enhanced mode) intelligently manages virtual memory to keep

the most-frequently used memory pages in physical memory. This management

speeds up the system.

Disadvantages of Removing Real Mode Support

-------------------------------------------

1. The installed base of 8088-based and 8086-based machines cannot

   use the software.

2. Code that performs segment arithmetic cannot be used in protected

   mode. Therefore, some drivers and MS-DOS programs that run in real

   mode must be rewritten for protected mode, or they cannot be run

   under Windows 3.1.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Retrieving MS-DOS Environment Vars from a Windows DLL

Article ID: Q78542

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The C run-time library function getenv() does not work when called

from a Windows dynamic-link library (DLL). MS-DOS environment variables

can be found by searching the environment block. This article explains

a method to retrieve information from environment variables.

NOTE: In Visual C++ version 1.0, getenv() does work correctly as long

as you do not link in LIBENTRY.OBJ (you need the default library

version that initializes the run time) and mark your DLL function as

_export to correctly load DS.

MORE INFORMATION

================

In a Windows system, an application's environment block is not

available to a DLL. For this reason, the getenv() C run-time library

function does not work when called from a DLL.

To gain access to environment variables, an application must use the

Windows GetDOSEnvironment() function, which returns a far pointer to

the environment block of the currently running task. Using this

pointer, the application can search the environment block for the

desired variable. The format of the environment block is as follows:

1. Each environment variable is followed by an equal sign (=), the

   contents of the variable, and a NULL terminator (\0).

2. The last environment variable in the block is terminated with two

   NULL characters.

An environment variable set with the following MS-DOS command

   set envvar=c:\this\is\a\test

is stored in memory as follows:

   ENVVAR=c:\this\is\a\test\0

MS-DOS converts environment variables to uppercase letters; therefore,

all searches for an environment variable must take this into account.

Below is source code to a function called DLLGetEnv() that acts as a

substitute for the getenv() function in a DLL:

/* forward declaration */

LPSTR FAR PASCAL DLLGetEnv ( LPSTR );

/*********************************************************************

*  DLLGetEnv ( lpszVariableName )                                    *

*                                                                    *

*  Takes a LPSTR to the name of an environment variable and returns  *

*  the contents of that variable. Returns NULL if the environment    *

*  variable does not exist. The search for the environment variable  *

*  is case sensitive.                                                *

*                                                                    *

*********************************************************************/

LPSTR FAR PASCAL DLLGetEnv ( LPSTR lpszVariableName )

  {

  LPSTR lpEnvSearch;

  LPSTR lpszVarSearch;

  if ( !*lpszVariableName )  //  Check for a NULL pointer

    return NULL;

                        //  Get a pointer to the MS-DOS environment block

  lpEnvSearch = GetDOSEnvironment ();

  while ( *lpEnvSearch )  //  While there are strings to parse

    {     /*

           *  Make a copy of the pointer to the name of the

           *  environment variable to search for.

           */

    lpszVarSearch = lpszVariableName;

              //  Check to see if the variable names match

    while ( *lpEnvSearch && * lpszVarSearch &&

            *lpEnvSearch == *lpszVarSearch )

      {

      lpEnvSearch++;

      lpszVarSearch++;

      }

        /*

         *  If the names match, the lpEnvSearch pointer is on the "="

         *  character and lpszVarSearch is on a null terminator.

         *  Increment and return lpszEnvSearch, which will point to the

         *  environment variable's contents.

         *

         *  If the names do not match, increment lpEnvSearch until it

         *  reaches the end of the current variable string.

         */

    if ( *lpEnvSearch == '=' && *lpszVarSearch == '\0' )

      return ( lpEnvSearch + 1 );

    else

      while ( *lpEnvSearch )

        lpEnvSearch++;

        /*

         *  At this point the end of the environment variable's string

         *  has been reached. Increment lpEnvSearch to move to the

         *  next variable in the environment block. If it is NULL,

         *  the end of the environment block has been reached.

         */

    lpEnvSearch++;

    }

  return NULL;  /*

                 *  If this section of code is reached, the variable

                 *  was not found.

                 */

  }

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Using Huge Pointers with Blocks of Memory Larger Than 64K

Article ID: Q79194

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The GlobalAlloc() function can be used to allocate memory blocks larger

than 64 kilobytes (64K). This memory can then be accessed using "huge"

pointers. For more information on huge pointers, see your Microsoft C

compiler documentation.

MORE INFORMATION

================

GlobalAlloc() always returns a single contiguous block of memory, if

it is possible to satisfy the request. This block can be accessed

using huge pointers. Huge pointers are composed of a segment:offset

address (real mode), or a selector:offset address (standard mode or

386 enhanced mode), just like a far pointer. Huge pointers allow

access to more than 64K, by adjusting the segment or selector part of

the address, as well as the offset.

In real mode, the segment address increases or decreases by 0x1000

every time the offset crosses the 64K boundary. In standard mode or

386 enhanced mode, memory is addressed using selectors instead of

segments. When GlobalAlloc() allocates a block of memory, it also

creates selectors to access that block. If the block of memory is

larger than 64K, GlobalAlloc() will create a set of tiled selectors.

The first selector in the set provides access to the first 64K of the

block. Subsequent selectors provide access to additional 64K portions

of the memory block.

Tiled selectors are allocated in a predefined pattern; the value of

the second selector equals the value of the first selector plus the

value of __AHINCR, and so forth. Therefore, when the offset of a huge

pointer crosses a 64K boundary in standard mode or 386 enhanced mode,

the value of the selector is increased or decreased by the value of

__AHINCR.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Retrieving the Names of Simultaneous Tasks Under Windows

Article ID: Q80124

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

There are situations when it is necessary for an application to obtain

a list of all applications that are running in the Windows environment

at a particular time.

In Windows 3.0, instead of using the EnumWindows() function and

an application-supplied callback function to enumerate all parent

windows, the application can retrieve a handle to the first window in

the task list and walk through the list to obtain the names of all

windows in the task list.

In Windows 3.1, however, an application should instead use the ToolHelp

Library functions. More specifically, use TaskFirst(), TaskNext(),

ModuleFirst(), and ModuleNext().

NOTE: Since the ToolHelp functions work in Windows 3.0 and since ToolHelp

is itself a redistributable library, these functions can be safely used in

Windows 3.0 also.

MORE INFORMATION

================

The most efficient way to retrieve the name of each task running under

Windows 3.0 is to use the GetWindow() function. GetWindow (hwnd,

GW_HWNDFIRST) provides the handle to the first window in the task list. The

application can walk through the task list by calling GetWindow

(hwndCurrent, GW_HWNDNEXT). The following example demonstrates how to

obtain a handle to each top-level window. The GetWindowText() function

provides the name of each window from its handle.

    hwndNext = GetWindow(hWnd, GW_HWNDFIRST);

    /* Where: hWnd is the original/current window. GW_HWNDFIRST will

       return the first sibling window for a child window, otherwise

       it returns the first top-level window in the system's list of

       top-level windows */

    while (hwndNext)

    {

       if ((hwndNext != hWnd) &&  // Do not get this application's

                                  // name.

           (IsWindowVisible(hwndNext)) &&

           (!GetWindow(hwndNext, GW_OWNER)))

       {

          if (GetWindowText(hwndNext, (LPSTR)szTemp, sizeof(szTemp)))

          {

            // This is a valid top-level window handle.

            // Its name is in szTemp...

          }

       }

       hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);

    }

The code above will retrieve the name of each visible window. To also

retrieve the names of invisible windows, remove the call to

IsWindowVisible().

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


Determining the Version of MS-DOS from a Windows App

Article ID: Q80783

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

There are at least three ways for an application developed for Windows

version 3.x to determine the version of MS-DOS that is running on the

system. Both the first and second methods require placing a few lines of

inline assembler code into the application. The second method requires MS-

DOS version 5.0. The third method requires changing the GetVersion()

function prototype in the WINDOWS.H header file distributed with the

Microsoft Windows SDK version 3.0 (this change is not necessary if the

Microsoft Windows SDK version 3.1 is being used).

Even though it is necessary to modify the Windows 3.0 header file, the

third method is the most removed from the hardware and can be considered

the most portable. The other two methods assume an underlying Intel 80x86

architecture (or emulation).

MORE INFORMATION

================

Method 1

--------

This method requires only a few lines of inline assembler code and a

call to the DOS3Call() function. The following code fragment

demonstrates this technique:

   VOID FAR PASCAL DOS3Call(VOID);   // Use instead of INT 21h

   int nMajor;                       // MS-DOS major version

   int nMinor;                       // MS-DOS minor version, revision

   int nOEMNumber;                   // OEM serial number

   static char szUserMsg[80];        // holds user message

   _asm

     {

        mov   ax, 0x3000        ; Get MS-DOS version

        call  DOS3Call

        mov   nMajor, al        ; Save major number

        mov   nMinor, ah        ; Save minor version number

        mov   nOEMNumber, bh    ; Save OEM Serial number

     }

   wsprintf(szUserMsg,

            "Running on MS-DOS %d.%d OEM Serial Number %d",

            nMajor, nMinor, nOEMNumber);

   MessageBox(hWnd, szUserMsg, "MS-DOS Version", MB_OK);

Method 2

--------

This method requires only a few lines of inline assembler code and a

call to the DOS3Call() function. Additionally, it requires that MS-DOS

version 5.0 is running on the system. While this function does not

report the OEM serial number, it does report whether MS-DOS is in ROM

or in HMA (the High Memory Area). Also the MS-DOS version returned by

this method is unaffected by the SETVER command. The following code

fragment demonstrates this technique:

   #define DOSINROM 0x08

   #define DOSINHMA 0x10

   int nMajor    = 0;

   int nMinor    = 0;

   int nRevision = 0;

   int nDOSFlag  = 0;

   static char msg[120];

   _asm

     {

         mov   ax, 0x3306        ; Get MS-DOS version

         call  DOS3Call

         mov   nMajor, bl        ; Save major number

         mov   nMinor, bh        ; Save minor version number

         mov   nRevision, dl     ; Revision num in low 3 bits

         mov   nDOSFlag, dh      ; MS-DOS version flags

     }

   wsprintf(msg,

            "Running on MS-DOS %s %s version %d.%d revision %d ",

            (LPSTR) (nDOSFlag & DOSINROM ? "in ROM " : ""),

            (LPSTR) (nDOSFlag & DOSINHMA ? "in HMA " : ""),

            nMajor, nMinor, (nRevision & 0x03));

   MessageBox(hWnd, msg, "MS-DOS Version", MB_OK);

Important Note for Methods 1 and 2

----------------------------------

The DOS3Call() function must be prototyped. In assembly language, the

appropriate prototype is as follows:

   extrn DOS3CALL: far

Use the DOS3Call() fucntion instead of making a direct call to MS-DOS

INT 21h. The DOS3Call() function runs a little faster than the equivalent

INT 21h call under Windows and it ensures that the interrupt will be

handled correctly under Windows.

Also note that the use of FAR and PASCAL in the definition of DOS3Call()

requires use of WINDOWS.H, since these macros are defined there.

Method 3

--------

The last method involves making a slight modification to the Windows SDK

version 3.0 header file, WINDOWS.H. To retrieve the MS-DOS version,

change the return type in the function prototype of the GetVersion

function call from a WORD to a DWORD. The modified prototype should

resemble the following:

   DWORD FAR PASCAL GetVersion(void);

NOTE: It is not necessary to make the above change to the version of

the WINDOWS.H file included with the Windows SDK version 3.1.

The following code fragment demonstrates how to use the GetVersion()

function to display both the MS-DOS version and the Windows version

numbers:

   DWORD dwVersion;

   char szUserMsg[80];

   dwVersion = GetVersion();

   wsprintf(szUserMsg,

            "Window version %d.%d. MS-DOS version %d.%d",

            LOBYTE(LOWORD(dwVersion)), HIBYTE(LOWORD(dwVersion)),

            HIBYTE(HIWORD(dwVersion)), LOBYTE(HIWORD(dwVersion)));

   MessageBox(hWnd, szUserMsg, "GetVersion", MB_OK);

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMisc


Modules, Instances, and Tasks

Article ID: Q81496

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following is the text of the article "Modules, Instances, and Tasks".

This article is available in Windows Help file format in the Microsoft

Software Library in addition to the text presented below.

MTI.EXE can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MTI.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735

      Download MTI.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MTI.EXE

                    Modules, Instances, and Tasks

                           by Bob Gunderson

ABSTRACT

--------

This article discusses modules, instances, and tasks. It covers the

following topics:

 - Definitions of module, instance, and task handles

 - Microsoft(R) Windows(TM) functions that deal with these handles

 - Exporting and the MakeProcInstance function

 - Task switching and yielding

OVERVIEW

--------

The Microsoft Windows graphical environment defines two types of

executable files: applications and dynamic-link libraries (DLLs). The

code in both types is normally sharable. Multiple instances of an

application or multiple users of a DLL can share code loaded by the

first instance. Most Windows-based applications and DLLs also contain

resources that are sharable in the same manner. When Windows loads an

application or a DLL into memory for the first time, it assigns a

unique identifier, called a module handle, or an hModule, to the

shared code and resources.

When Windows loads an application, it creates a unique execution

context for the application to distinguish it from other running

copies of the same application. This execution context is given an

identifier called an instance handle, or an hInstance. Part of the

execution context for an application is its automatic data segment,

where the application's static data, stack, and local heap reside. Two

running copies of an application share code, but each has its own data

segment. DLLs differ from applications in that all instances of a DLL

share the same execution context, and therefore share a common data

segment.

Part of the execution context of an application is defined by a set of

CPU registers and a stack. This portion of the execution context (a

task context) is given a special identifier called a task handle, or

an hTask. Every loaded application has its own task handle, but task

handles are never associated with DLLs. Therefore, the automatic data

segment of a DLL never contains a stack.

Windows can easily obtain a module handle from an instance handle

because an execution context is always associated with only one

module. Because a module can have more than one running instance,

however, obtaining an instance handle given only the module handle is

impossible.

DEALING WITH HMODULE AND HINSTANCE

----------------------------------

Module and instance handles are used inconsistently in the Microsoft

Windows Software Development Kit (SDK) documentation. For example,

LoadLibrary is documented to return an hInstance, but FreeLibrary

takes an hModule. How can you free a library if Windows provides no

obvious way to convert an hInstance to an hModule?

A number of the Windows-based application programming interfaces (APIs)

that are documented as accepting only a module handle are defined

incorrectly: Most can take an instance handle or a module handle.

FreeLibrary, for example, can accept either a module handle or an

instance handle. The following APIs are documented incorrectly; the

following short descriptions of what the function does are correct:

   DeviceMode,         Obtain and set printer configuration data. Pass

   ExtDeviceMode       the hModule or the hInstance of a printer driver.

                       (Printer drivers are simply DLLs.)

   FreeLibrary         Identical to FreeModule but is provided for

                       symmetry with LoadLibrary. FreeLibrary accepts

                       either an hModule or an hInstance. Usually only

                       DLLs that are loaded by LoadLibrary are freed with

                       FreeLibrary because implicitly loaded DLLs are

                       freed by Windows when the application using the

                       DLL is terminated.

   FreeModule          Normally called with an hInstance but also takes

                       an hModule. For applications, all instance-

                       specific data associated with the hInstance passed

                       is freed. FreeModule also decrements the usage

                       count of the associated module, and if the usage

                       count becomes 0, the module is freed. For DLLs,

                       the window exit procedure (WEP) is called, and

                       instance-specific data is freed before the module

                       is freed. The FreeModule function should have been

                       named FreeInstance.

   GetModuleFileName   Returns the full path of the executable file (EXE

                       or DLL) for a module. This API takes either an

                       hModule or an hInstance.

   GetModuleHandle     Returns the hModule of a module given the module

                       name or an instance handle. The module name is not

                       always the same as the filename of the file from

                       which the module was loaded. The module name is

                       specified in the module definition file (DEF) when

                       the module is created (NAME and LIBRARY

                       statements). Most, but not all, applications and

                       DLLs specify a module name that is equivalent to

                       its root filename (the filename without the

                       extension). Modules that have different module

                       names and filenames may experience problems when

                       the module is debugged because some debuggers

                       assume they are equivalent. You can use an

                       instance handle in place of the module name by

                       passing the hInstance in the low word and a NULL

                       in the high word of the lpModuleName parameter.

   GetModuleUsage      Returns the usage count of a module. This function

                       accepts either an hModule or an hInstance. The

                       usage count is incremented each time a new

                       instance of the module is loaded, and it is

                       decremented each time an instance is freed.

   GetProcAddress      Obtains the address of a specified function in a

                       module. Either an hModule or an hInstance can be

                       passed to the function.

   LoadLibrary         Loads a DLL. If the DLL is not already loaded,

                       LoadLibrary creates a module and an execution

                       context for it. If the DLL is already loaded,

                       LoadLibrary simply increments the module's usage

                       count (no new execution context is created because

                    all instances of a DLL share the same execution

                       context). In both cases, the function returns the

                       hInstance for the DLL.

   LoadModule          Loads an application. If the application is

                       already loaded, LoadModule increments the module's

                       usage count and creates a new execution context

                       and task context. This function returns the

                       hInstance of the application just started.

   WinExec             Operates exactly the same as LoadModule but is

                       easier to use.

At this point you may be asking, "If an instance handle can be used in

place of a module handle, why have module handles at all? Why not just

have instance handles and be done with it?" Good question. The answer

is that it really doesn't matter. You can just write applications

using instance handles rather than module handles for the functions

above. This is good news because instance handles are much easier to

obtain than module handles. For example, calling GetWindowWord with

GWW_HINSTANCE obtains the instance handle of the application or the

DLL that created a window. This instance handle can then be used to

determine the module filename of the application that created the

window. No equivalent way exists to do this using module handles.

Actually, module handles have a real use. Internally, Windows uses

module handles to tag certain resources, such as window classes and

hooks, that are associated with a module and not with a particular

instance of a module. These resources are not freed until the last

instance of the module is freed.

Although undocumented in Windows version 3.0, obtaining a module

handle from an instance handle is possible. Calling the

GetModuleHandle function with the low word of the lpModuleName

parameter set to an hInstance and the high word of the same parameter

set to NULL returns the module handle of the specified hInstance. The

version 3.1 WINDOWS.H file contains a macro, GetInstanceModule, that

does this for you.

INSTANCE HANDLE API FUNCTIONS

-----------------------------

The following Windows functions deal with instance handles:

   Resource functions:      AccessResource, AllocResource, CreateIcon,

                            FindResource, LoadAccelerators, LoadBitmap,

                            LoadCursor, LoadIcon, LoadMenu, LoadResource,

                            LoadString, SetResourceHandler,

                            SizeofResource

   Window functions:        CreateDialog, CreateDialogParam,

                            CreateDialogIndirect,

                            CreateDialogIndirectParam, CreateWindow,

                            CreateWindowEx, DialogBox, DialogBoxParam,

                            DialogBoxIndirect, DialogBoxIndirectParam

   Class functions:         GetClassInfo, RegisterClass, UnregisterClass

   Miscellaneous functions: GetInstanceData, MakeProcInstance, WinMain

EXPORTED FUNCTIONS

------------------

Execution usually enters a module's code through exported entry

points. If an application has multiple instances, the exported entry

points must be able to set the proper data segment upon entry. This

applies to all functions that are the target of a call from another

module, such as functions in an application that Windows calls (dialog

procedures, callback functions, and so on). But exporting alone is not

enough to set the proper data segment. For each instance of the

application, these functions need a unique entry point, which can set

the proper data segment and then jump to the "real" function. The

MakeProcInstance function is used for this purpose. It takes a pointer

to an exported function and an instance handle and creates a call

thunk. A call thunk is merely a piece of code that moves the specific

instance's data segment value into the AX register and then jumps to

the real function. Exported functions expect the appropriate data

segment value to be passed in the AX register, and move the value to

the DS register in the function prolog. The application uses the

pointer to the call thunk returned by MakeProcInstance in place of the

pointer to the real function in calls such as DialogBox and

EnumWindows.

Window procedures do not need call thunks. When an application creates

a window, it supplies an hInstance value on the CreateWindow call.

This value is saved internally, and Windows uses it to set the proper

AX value before dispatching messages to a window procedure. Dialog

procedures, on the other hand, are not real window procedures and do

need call thunks.

Exported functions that reside in a DLL also don't require call

thunks. Because all users of a DLL share the same instance, creating

call thunks for them is not necessary.

TASKS

-----

A task can be thought of as a "logical CPU" with its own CS:IP, stack,

and registers. A task can execute code from any number of modules. As

execution enters a module (usually through an exported entry point),

the current task handle remains unchanged, but the function's prolog

code sets the proper execution context, that is, the proper data

segment.

Task switching occurs when an application calls a Windows function

that gives up control of the system, a procedure known as yielding.

Because Windows is a nonpreemptive multitasking system, applications

must periodically give up control of the system to allow other

applications to run. The following functions can cause the calling

task to yield:

 - DialogBox, DialogBoxParam, DialogBoxIndirect, DialogBoxIndirectParam

 - DeviceMode, ExtDeviceMode (These can display a dialog box.)

 - GetDC (Only if all device contexts [DCs] are in use.)

 - GetMessage, PeekMessage, WaitMessage

 - MessageBox

 - Yield

Along with the functions on this list, any function that sends a

message to another application (such as SendMessage) can cause a

temporary task switch while the target application processes the

message. Few Windows functions deal with tasks. Applications seldom

need to obtain or use their task handle. Usually, task handles are

used only for identification. The only functions that accept or return

task handles are GetCurrentTask, EnumTaskWindows, and PostAppMessage.

Enumerating all tasks currently running is not possible, using the

standard Windows functions. Applications that need this information

can use the Toolhelp library, which provides a function for this

purpose.

Because DLLs are not instanced under Windows (that is, all instances

share the same DS), creating a server-type DLL that can provide

services to multiple simultaneous clients is not straightforward. The

problem is knowing which client is requesting service at any point.

Some DLLs call the GetCurrentTask function to retrieve the current

task's hTask and then tag a data structure or some other data item

with this task handle. Then, each time a request for service is made,

the DLL checks its list of known client task handles with the current

task. This solution has only one flaw. Task handles are actually

global handles to an internal data structure that describes the task.

Global handles can be reused. If one task terminates and another

starts, the new task can have the same task handle as the task just

terminated. This is not a problem to a server DLL as long as the DLL

knows that the original task terminated. Even if a client application

is written to disconnect from a server DLL before terminating, an

abnormal termination of the application can still cause the problem

just described. In this case, the server DLL doesn't know the task

terminated. Rather than hacking around this problem, DLLs in this

situation can easily use the Toolhelp notification services to detect

when a particular task terminates.

Copyright 1992 by Microsoft Corporation.  All rights reserved.

Additional reference words: 3.00 3.10 softlib MTI.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrTsksIns


PRB: Segment Was Discardable Under 3.0 Notification

Article ID: Q81546

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The debugging version of Microsoft Windows version 3.1 writes the

following notification to the debugging terminal:

   Segment was discardable under 3.0

CAUSE

=====

One or more code segments of a dynamic-link library (DLL) are marked

MOVEABLE and are not marked DISCARDABLE.

RESOLUTION

==========

Modify the module definition (.DEF) file for the DLL to mark all MOVEABLE

code segments as DISCARDABLE.

MORE INFORMATION

================

Under Windows version 3.0, MOVEABLE code segments in a DLL are DISCARDABLE

by default. This behavior changes under Windows 3.1; segments must be

marked DISCARDABLE to be discarded. The debug notification highlights the

change in behavior between the two versions of Windows.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrMm


Limits on the Number of Open Files

Article ID: Q81577

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Because an application developed for the Windows graphical environment

runs only within the MS-DOS environment, the number of files that the

application can open is subject to two distinct limits imposed by

MS-DOS. This article discusses these limits.

MORE INFORMATION

================

The first limit on the number of open files is imposed by a table of

SFT data structures (System File Tables) within MS-DOS. The initial

number of SFTs is specified in the FILES= line of the CONFIG.SYS file.

MS-DOS version 5.0 does not provide a function to change the number of

SFTs in the table. However, some applications, including Windows,

contain the information necessary to change the size of the table.

The SFT table is global, that is, it is shared by all applications or

tasks that are active in the system. (Each task is represented by a

PSP or program segment prefix.) The exception to the global nature of

the SFT table, and the associated limit on the number of open files,

in introduced by Windows. Different groupings of applications, called

virtual machines (or VMs), have a "per VM" address space. This allows

a virtual machine to have a local portion of the SFT table, which

exists only in that VM. Because all graphical applications in the

Windows environment run in a single VM, only the MS-DOS (not

graphical) applications run in separate VMs.

MS-DOS does not support more than 255 SFTs. Therefore, it does not

support more than 255 open files at any time in any specific VM. The

SHARE utility, which extends MS-DOS core functionality, does not

support the ability to increase the size of the SFT table on a "per

VM" basis under Windows, because SHARE must, at any time, in any VM,

be able to enumerate all open SFTs in the entire system.

The second limit on the number of open files involves a "per

application" table, called the JFN table, which is stored in each

task's PSP. By default, the JFN in the PSP has room for 20 entries,

which limits each application to 20 open files. An application running

on MS-DOS version 3.3 and subsequent versions can change the size of

the JFN by calling MS-DOS INT 21h function 67h. This call allocates a

new JFN table and modifies values in the PSP to indicate the larger

size of the JFN table. This allows the application corresponding to a

particular PSP to open more than 20 files, provided that the global

SFT table, shared by all applications, has available SFTs.

The two limits work together as follows. First, to open a file, the

application must have a place available in its JFN table. Second,

MS-DOS must have an available SFT in its internal SFT table. Note that

if either of these requirements is not met, the OPEN (or CREATE) INT

21h call will fail with error 4.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Hooking Interrupt 21h Before Windows

Article ID: Q81813

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

In the standard and enhanced modes of Microsoft Windows version 3.1, an

application for Windows can receive notification of all calls to MS-DOS

made by Windows after these calls have been translated by the Windows

kernel. To do so, the application calls the MS-DOS Protected Mode Interface

(DPMI) to hook the real mode Interrupt 21h vector.

MORE INFORMATION

================

This technique is not effective in standard mode under Windows version 3.1

because the Windows 3.1 Standard Mode MS-DOS Extender (DOSX) does not use

the real mode interrupt vector table (IVT) to translate software interrupts

from protected mode to real mode. DOSX uses a copy of the real mode IVT,

made at DOSX initialization, for this purpose.

In addition, receiving notification using DPMI is of questionable validity

because future versions of Windows may implement some or all software

interrupts in protected mode. (The Windows 3.1 kernel already implements

Interrupt 13h in protected mode, when 32-bit disk access is enabled.)

Applications that must receive notification of Interrupt 21h after the

Windows kernel can use the GetSetKernelDOSProc() function provided by

the standard and enhanced modes of Windows 3.1. This function sets the

protected mode address that the kernel calls to implement Interrupt

21h. The prototype of GetSetKernelDOSProc() is as follows:

   DWORD _far _pascal GetSetKernelDOSProc(DWORD newproc);

The newproc parameter is the protected mode address of the new Interrupt

21h interrupt routine, which kernel calls to implement Interrupt 21h.

GetSetKernelDOSProc() returns the address of the old routine, which kernel

called previously. If the application processes only particular Interrupt

21h functions, it must send unprocessed functions to the next handler in

the chain. Use the address returned by GetSetKernelDOSProc() to call the

next handler in the chain.

An application calls GetSetKernelDOSProc() once to install itself as the

Interrupt 21h handler, saving the return value. When the function exits, it

calls the function again to restore the previous value. An application that

can uninstall itself should verify that GetSetKernelDOSProc() returns the

value of its handler when called to restore the previous handler. If

GetSetKernelDOSProc() returns a different value, another program has

installed itself into the Interrupt 21h chain. If so, the application

should call GetSetKernelDOSProc() a third time to place itself back into

the Interrupt 21h chain.

An application that hooks real mode Interrupt 21h in Windows 3.0

should use GetSetKernelDOSProc() in Windows 3.1 and later versions.

Although GetSetKernelDOSProc() is not in LIBW.LIB, it is exported as

ordinal 311, which is the preferred method to link to the function.

The other method is to use GetProcAddress() with the function name.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrDosint


Windows 3.1 Standard Mode and the VCPI

Article ID: Q82298

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows 3.1 standard mode is compatible with expanded memory managers

such as EMM386, 386MAX, and QEMM386. However, there are several

problems with the Virtual Control Program Interface (VCPI) used by

these products to provide access to extended memory in standard mode.

Under most circumstances, users of machines with 386 or higher

processors and with more than 2 megabytes (MB) of memory installed

should use enhanced mode rather than standard mode.

MORE INFORMATION

================

Windows 3.1 can run in standard mode when an expanded memory manager

(EMM) is active. An EMM uses the paging mechanism of the 386 or higher

processor to map extended memory blocks, as EMS pages, into the first

megabyte of address space where no real memory is present. To do so,

the EMM puts the processor into protected mode, and keeps the emulated

upper memory block (UMB) and EMS page frames always available for

processes designed for real mode (such as MS-DOS), installed device

drivers, and terminate-and-stay-resident (TSR) programs. When one of

these processes is running, the processor is in virtual-8086 (v86)

mode, with paging on and the address mapping specified by the EMM.

In this configuration, the EMM services request to enter and leave

protected mode using the VCPI. The EMM may also allocate extended

memory. The standard mode MS-DOS Extender, DOSX, uses VCPI to switch

to protected mode and to v86 mode. Therefore, in standard mode, the

EMM remains active and continues to run "underneath" Windows. In

enhanced mode, the EMM is deactivated for the duration of the Windows

session.

Several questions have arisen regarding "VCPI support" under

standard-mode Windows. If no EMM is installed, more extended memory

and more total memory is available to Windows. An EMM uses a

considerable amount of extended memory to store itself and its tables.

The system incurs additional overhead because paging must be active at

all times. Unless an EMM is absolutely necessary, possibly because an

MS-DOS-based application will not run without EMS, Windows will probably

run better without an EMM. Windows enhanced mode runs on a machine with 2

MB of RAM memory installed if no EMM is present.

Windows standard mode does not support an MS-DOS-based application that is

a DPMI (DOS Protected Mode Interface) client. However, if the EMM

also provides DPMI services, DOSX will not interfere with these

services.

The standard-mode task switcher attempts to arbitrate extended memory

use between Windows-based and MS-DOS-based applications. It performs this

arbitration by hooking the XMS function dispatcher. This does not work

properly if an EMM is installed, primarily because the extended memory

portion of the address space in standard mode is not accessible to the

MS-DOS portion of the switcher. For this reason, when an EMM is

present in standard mode, users will experience the following types of

problems:

 - Performance degradation when the system switches between tasks

   because the task switcher cannot use XMS memory for swap space.

 - Applications, such as AutoCad and Lotus 1-2-3, that include an

   MS-DOS extender will not run.

Because the standard-mode task switcher can't access Windows's

extended memory, it can't use extended memory for swap space when an

EMM is present. Users may experience some performance degradation

switching between MS-DOS-based applications in this configuration. Enhanced

mode is recommended to run many MS-DOS-based applications under Windows.

Windows standard mode does not specifically prevent VCPI applications

from running. However, because the task switcher cannot effectively

use extended memory provided by an EMM, an MS-DOS-based application that

uses extended memory probably will fail to run in the standard-mode

MS-DOS box. This applies equally to applications that use XMS, VCPI,

and DPMI. While it may be possible to run an MS-DOS-based application that

uses extended memory in an MS-DOS box under standard-mode Windows,

there is no general solution to the problems involved.

The VCPI specification is maintained by Phar Lap Software, Inc., and

Quarterdeck Office Systems. Windows 3.1 standard mode complies with

version 1.10 of the VCPI specification. Because many commercial EMM

products can be configured to not provide EMS, DOSX will attempt to

use VCPI if the following are true:

 - The INT 67h vector is not null

 - A device named "EMMXXXX0" is present

 - The VCPI detection call (INT 67h, AX=DE00h) succeeds

In particular, DOSX does not require the presence of a LIM 4.0

(Lotus/Intel/Microsoft expanded memory specification) driver or a LIM

3.2 page frame.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMm


XMS Calls Under Windows 3.1

Article ID: Q83008

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

When enhanced mode Windows is running, the WIN386 module answers all

extended memory specification (XMS) calls. The standard mode MS-DOS

Extender (DOSX) answers all calls only in protected mode.

The standard mode task swapper answers memory allocation calls to

arbitrate the use of extended memory between Windows and MS-DOS

applications, and to facilitate task swapping.

MORE INFORMATION

================

Windows enhanced mode provides its own XMS services, without regard to

the XMS driver that was installed before Windows started up. The

amount of XMS memory available in an MS-DOS window under enhanced mode

is determined by the PIF (program information file) settings, and not

by the amount of memory actually available in the system. The enhanced

mode XMS driver returns failure for all XMS Lock Region calls, because

enhanced mode XMS uses virtual memory rather than physical memory.

In standard mode, the task swapper hooks the XMS driver, allowing it

to arbitrate XMS use between Windows-based and MS-DOS-based applications.

Most XMS calls are passed through to the original XMS driver. However,

calls that manage extended memory are affected by the PIF settings. Because

it hooks the XMS driver, the standard mode task swapper can use

extended memory allocated to Windows, but not currently in use, for

swapping. This feature is disabled if a "limulator"

[Lotus/Intel/Microsoft (LIM) standard expanded memory system driver]

is present.

The standard mode MS-DOS extender hooks XMS detection in protected

mode. The INT 2Fh call that retrieves the address of the XMS driver's

control function (AX=4310h) returns a protected mode address that an

application can call to perform XMS control functions. This is

intended for the use by application installation programs that must

determine the version number of an installed XMS driver. Applications

in the Windows environment are discouraged from making other XMS calls

in protected mode. In particular, attempting to lock XMS memory in

standard mode may result in a page fault or fatal system crash.

Additional reference words: 3.10 switcher

KBCategory: kbprg

KBSubcategory: KrMm


Retrieving Application Exit Code in MS-DOS Window

Article ID: Q83301

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Under Windows version 3.1, the value returned by an MS-DOS-based

application is available to other applications in the system. Under Windows

version 3.0, however, this value is not available; the exit code returned

is always zero.

MORE INFORMATION

================

Windows supports an MS-DOS window in which to run MS-DOS (non-Windows)

applications. The WINOLDAP module serves as an interface for the

application and the remainder of the Windows environment. When the

MS-DOS-based application terminates, WINOLDAP retrieves the application's

exit code. Then WINOLDAP itself terminates, using the retrieved exit

code as its own exit code.

An application developed for the Windows environment can retrieve the

exit code from WINOLDAP. The application defines a call-back function

and calls the NotifyRegister function in the tool helper library

(TOOLHELP.DLL). The call-back function will receive an NFY_EXITTASK

message containing the exit code each time a task terminates.

The Windows 3.1 WINOLDAP module can return a number of error codes

which are listed and explained in the "Microsoft Windows Software

Development Kit Programmer's Reference Volume 1," page 277.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrWoa


PRB: XMS Version Information in MS-DOS Window Incorrect

Article ID: Q83455

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In an MS-DOS window under Windows, the version number of the extended

memory system (XMS) driver is not the installed XMS driver (started before

Windows is started). It is a version of the XMS manager built into Windows.

The same thing is true for the expanded memory system (EMS) driver, the DOS

Protected Mode Interface (DPMI), and any other drivers that enhanced mode

Windows virtualizes.

CAUSE

=====

This is by design. When Windows starts, it takes over all the XMS memory

from the original XMS, EMS, and DPMI drivers. When you open an MS-DOS box,

Windows provides extended memory to the MS-DOS-based application. NOTE: The

XMS manager is XMS 2.0 compliant.

RESOLUTION

==========

It is not possible to retrieve the version number of the original provider.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrMm


Memory Use Limitations in Microsoft Windows

Article ID: Q84778

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Windows 3.0 can access up to 16 megabytes (MB) of physical memory.

With the release of version 3.1, Windows can access more than 16 MB of

physical memory. This article discusses the factors that influence the

amount of memory available to applications in the Windows environment.

MORE INFORMATION

================

In enhanced mode, Windows versions 3.0 and 3.1 can use features of the

Intel 386 (and compatible) microprocessors to supplement the installed

physical RAM memory with virtual memory in a disk-based swap file. As

physical memory fills, Windows sends the least-recently used pages of

memory to disk. When this data is later accessed, Windows pages it

back in from disk. This activity is transparent to applications in the

system.

Windows 3.0 cannot address any memory with an address higher than

100000h (16 MB). Windows 3.1 can address at most 256 MB of physical

RAM memory, and the largest swap file Windows 3.1 will ever create is

256 MB. To be used by Windows 3.1, all physical RAM memory must

have an address lower than 7FC00000h (2,044 MB).

While the combination of 256 MB of physical RAM memory coupled with a

256 MB swap file provides a theoretical limit of 512 MB, the actual

maximum is somewhat less than 512 MB.

The architecture of the Intel 386 processor defines a Local Descriptor

Table (LDT), which is used in the memory protection scheme. Windows

3.1 uses one LDT that provides 8192 descriptors. Each descriptor can

describe a block of memory containing at most 64 KB. While multiplying

the number of descriptors by the maximum amount of memory yields the

512 MB theoretical limit again, Windows will not access this much

memory for the following two reasons:

 - Windows reserves some descriptors for its own use.

 - Most memory allocations that use a descriptor do not allocate the

   64K maximum allowed.

Both of these factors reduce the number of available descriptors and

the amount of memory that Windows can use.

While the About dialog box in the Program Manager reports an estimate

of the amount of memory available, Windows does not maintain

sufficient information to accurately report the amount of free memory

at any given time. Maintaining more accurate information regarding the

amount of free memory would seriously degrade system performance

because memory is allocated and freed very frequently.

The values reported by the GetFreeSpace and GlobalCompact functions

are less than or equal to the amount of free memory available in the

system. Because of their imprecise nature, an application should use

the value reported by one of these functions only for an informational

display. The application must not assume that it is possible to

allocate that much memory.

The largest block of memory that an application can allocate is

affected by the degree of memory fragmentation. Memory available in

fixed portions of memory may be available for allocation only as a

fixed block. For example, consider the case where the GetFreeSpace

function returns 100K available, and 64K of the available space is

located in the fixed portion of the heap with the remainder in the

movable and discardable portion of the heap. An attempt to allocate a

100K block of movable and discardable memory will most likely fail.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


PRB: DLL Function Returns Float or Double Value Incorrectly

Article ID: Q86081

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When a function using the C calling convention and exported from a dynamic-

link library (DLL) returns a data value of type float, double, or long

double, the calling application receives unexpected values.

CAUSE

=====

The pointer used to return a floating-point result under the C calling

convention is invalid once control returns to the application.

RESOLUTION

==========

Declare the DLL function using the Pascal calling convention or allocate

memory from the global heap to hold the floating-point result and return

the handle from the DLL function.

MORE INFORMATION

================

The DLL and any application that calls the DLL each have separate

floating-point accumulators. When an application calls a DLL function

declared with the Pascal calling convention, the application allocates

space on the stack to receive the returned data type. The DLL function

pushes the value onto the stack for the application to use.

When an application calls a DLL function that uses the C calling

convention, no stack space is allocated because the calling function

cleans up the stack. Under the C calling convention, the DLL function

returns a pointer (in DX:AX) to the floating-point accumulator, which

contains the result. However, once the application regains control,

the pointer is not valid.

The code examples below demonstrate returning a float value under the

C and Pascal calling conventions:

C Calling Convention

--------------------

// C calling convention - DLL

// Compile options required: /Asw /G2sw /Zp

HANDLE _far floatcalc(float fl1, float fl2);

HANDLE _far floatcalc(float fl1, float fl2)

{

   HANDLE hFloat;

   float _far *pFloat;

   hFloat = GlobalAlloc(GMEM_MOVEABLE, sizeof(float));

   pFloat = (float _far *)GlobalLock(hFloat);

   *pFloat = fl1 * fl2;

   GlobalUnlock(hFloat);

   return hFloat;

}

// C calling convention - Application

// Compile options required: /AS /G2sw /Zp

extern HANDLE _far floatcalc(float fl1, float  fl2);

void Calc(void)

{

   float _far *pFloat, fl;

   HANDLE lFloat;

   lFloat = floatcalc((float)3.0, (float)4.1);  // Call DLL function

   pFloat = (float _far *)GlobalLock(lFloat);

   fl = *pFloat;

   GlobalFree(lFloat);

}

Pascal Calling Convention

-------------------------

// Pascal calling convention - DLL

// Compile options required: /Asw /G2sw /Zp

float _far _pascal FloatCalc(float fl1, float fl2);

float _far _pascal FloatCalc(float fl1, float fl2)

{

return fl1 * fl2;

}

// Pascal calling convention - Application

// Compile options required: /G2sw /Zp

extern float _far _pascal FloatCalc(float fl1, float fl2);

void Calc(void)

{

   float temp;

   temp = FloatCalc((float)3.1, (float)4.2);  // Call DLL function

}

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb kbcode

KBSubcategory: KrFltPt


PRB: Avoiding "Insufficient Memory to Run" Errors

Article ID: Q86230

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

During the process of loading an application, Microsoft Windows

displays an application execution error message box with the

following message:

   Insufficient memory to run this application; close one or more

   Windows applications and try again.

CAUSE

=====

One of the reasons this message is displayed is that the system has

no memory available with an address less than 1 megabyte (MB). When

Windows loads an application, it calls the GlobalDosAlloc() API

to allocate memory in the address space below 1 MB for the

application's task database. If the GlobalDosAlloc() call fails,

Windows displays the application execution error message.

RESOLUTION

==========

Use as little memory below 1 MB as possible.

MORE INFORMATION

================

A common situation that leads to an insufficient memory error regards

an application developed using a large memory model that includes many

extra data segments and/or very large extra data segments. When

Windows loads the application, it allocates fixed memory to hold the

extra data segments. In Windows 3.0, these fixed memory blocks are

also page locked, which prevents the memory manager from moving the

blocks to disk as memory fills.

Fixed memory is allocated from the bottom of the global heap, which

starts at the lowest possible memory address. If all the memory below

1 MB is filled with page locked memory blocks, Windows cannot move

blocks in memory or swap blocks to disk to free any memory. When

Windows cannot allocate a task database for a new task, it displays

the error message box discussed above.

For more information on the page locking of fixed memory segments in

Windows, please see the following article(s) in the Microsoft Knowledge

Base:

   ARTICLE-ID: Q72584

   TITLE     : PRWIN9105005: Windows Page Locks GMEM_FIXED Memory

An application can determine whether all memory addressed below 1 MB

is in use by attempting to allocate a small block of memory with the

GlobalDosAlloc function. (Windows 3.0 requires 512 bytes of low memory

for the task database of each application.) If the allocation fails,

Windows will not be able to start another program. Even if the

allocation is successful, the failure of another memory allocation

required by the application may prevent it from loading.

One way to address this problem is to remove the page lock from an

application's extra data segments. However, memory accessed by an

interrupt service routine must be page locked to keep its data

available at all times. An application can use the services of the

tool helper dynamic-link library (TOOLHELP.DLL) and a few Windows

functions to modify the flags on the extra data segments. After

modification, the data segments are movable and not page locked.

Use the GlobalFirst() and GlobalNext() functions provided by the tool

helper library to walk the global heap looking for memory blocks owned

by the application. If a memory block is page locked (the wcPageLock

field of the GLOBALENTRY data structure is not zero), call the

GlobalPageUnlock function to change the lock count for the memory

block. Calling GlobalRealloc() to change the block from fixed to

movable memory might also be desirable.

For more information on the tool helper library, see Chapter 8 of the

"Microsoft Windows Software Development Kit: Programmer's Reference,

Volume 1: Overview" version 3.1 manual.

Another method to unlock data segments uses the GlobalPageUnlock() and

GlobalUnfix() functions. For more information on this technique, please see

the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q83363

   TITLE     : Sample Code Unlocks Large-Model Extra Data Segments

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrToolHlp


Redirecting Debugging Information Under Windows 3.0, 3.1

Article ID: Q86263

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Each new application for the Microsoft Windows environment should be

tested under the Windows debugging kernel. When an application

performs an illegal or potentially harmful operation, the debugging

kernel traps the error and provides a descriptive message about the

source of the problem. By default, the debugging kernel sends its

messages to the AUX device (which maps to the COM1 port). This article

describes how to redirect output from the debugging kernel under

Windows versions 3.0 and 3.1.

MORE INFORMATION

================

As noted above, in the Windows 3.0 and 3.1 environments, the debugging

kernel sends its data to the AUX device, which (in general) maps to

the COM1 port. One method to display this debugging information is to

connect a serial communications terminal or another computer running a

terminal emulation program to the COM1 port. Before running Windows,

set the port's parameters appropriately through the MS-DOS MODE

command. Placing the MODE command in the AUTOEXEC.BAT file

automatically sets the port's parameters.

When the debugging kernel starts, if no device is connected to COM1,

the kernel displays a "Cannot write to device AUX" message box. If the

COM1 port is dedicated to another use and cannot be connected to a

serial terminal, you can configure the debug kernel to send its

messages elsewhere. The remainder of this article explains the

procedures required.

Moreover, if you do not have a serial terminal connected to the COM1

port, then before starting the debug version of Windows, ensure that

the following lines are added to the [Windows] section of the WIN.INI

file:

   DebugOptions=0x0000

   DebugFilter=0x0000

   DebugTaskFilter=       ;leave it blank

and the following new section to your SYSTEM.INI file:

   [Debug]

   OutputTo=NUL

The setting for the OutputTo entry in the SYSTEM.INI disables the

default debug Kernel output to the AUX device (which maps to COM1 port).

It is a good idea to do this, since DBWIN Windows sample application can

be used to redirect output to either COM1 or COM2 port.

The setting for the DebugOptions entry corresponds to the values for the

dwOptions member of the WINDEBUGINFO structure in the Windows SDK. The

setting for the DebugFilter entry corresponds to the values for the

dwFilter member of WINDEBUGINFO. To determine the proper hexadecimal value

for a setting, add the values of the options to be set. For example, to

specify DBO_CHECKHEAP and DBO_FREEFILL, the setting for the DebugOptions

entry would be 0x0021 (0x0001 + 0x0020). For information about the possible

values for these options and a full description of the WINDEBUGINFO

structure, see the Microsoft Windows Programmers Reference, Volume 3.

Windows 3.1

-----------

In the Windows 3.1 environment, the debugging terminal is not

required. The Windows 3.1 debugging kernel provides two methods to

redirect debugging information:

1. Redirect the debugging information from COM1 into a file by

   specifying the following in the [Debug] section of the SYSTEM.INI

   file:

      OutputTo = <filename>

   To disable sending debug messages to AUX, specify the following in

   the SYSTEM.INI file:

      OutputTo = NUL

2. Version 3.1 of the Microsoft Windows Software Development Kit (SDK)

   includes the DBWIN sample program in the advanced samples directory

   (by default, C:\WINDEV\SAMPLES). DBWIN provides a good interface

   and some useful features to debug an application in the Windows

   environment. DBWIN can disable sending debugging messages to AUX or

   redirect the debugging messages to any of the following:

    - The COM1 port

    - The COM2 port

    - A window on the primary display

    - A secondary monochrome monitor

   These redirection options are listed on the Options menu. When

   using DBWIN, choose Settings from the Options menu and verify that

   the Break On Traces option is not selected. For more information on

   DBWIN, see the DBAPI.TXT and DBWIN.TXT files in the DBWIN

   directory, Appendix C of the "Microsoft Windows Software

   Development Kit: Programming Tools" version 3.1 manual, and the

   online help files.

Windows 3.0

-----------

Windows 3.0 does not provide a built-in method to redirect debugging

output; external measures are required.

This article outlines two methods to redirect output under Windows

3.0. The first is through the WINAUX.SYS device driver that redirects

debugging output into a window on the main display, similar to the

DBWIN application discussed above. The second is through the OX.SYS

device driver that redirects debugging output to a secondary

monochrome adapter connected to the system.

The WINAUX.SYS device driver is the method of choice.

Download WINAUX.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINAUX.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINAUX.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINAUX.EXE

To install WINAUX.SYS, place the following line in the CONFIG.SYS

file:

   DEVICE=WINAUX.SYS

Another method to redirect debugging output under Windows 3.0 is to

use the OX.SYS device driver that redirects output for the AUX device

to a monochrome video adapter. Many development systems have a

secondary monochrome display to use with CodeView for Windows (CVW).

OX.SYS sends the debug messages to the monochrome display.

The OX.SYS file and its source code is available in the Software

Library. If necessary, you can modify the OX source code to direct

debugging output to another device such as LPT1, COM2, and so on.

Download OX.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for OX.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download OX.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get OX.EXE

To install OX.SYS, add the following line to the CONFIG.SYS file:

   DEVICE=OX.SYS

Under Windows 3.0, OX.SYS is limited because it provides an input-only

or output-only device. Therefore, when the Windows debugging kernel

provides output for a FatalExit message followed by the "Abort, Break,

Ignore?" prompt, OX.SYS cannot obtain the user's response. Third-party

developers have developed bi-directional device drivers to address

this limitation and have placed the drivers into the public domain.

Two examples are WINRIP.SYS and MONO-DRV.SYS.

Additional reference words: 3.00 3.10 softlib OX.EXE WINAUX.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDebug


No MS-DOS Extended Error Info for Windows File Functions

Article ID: Q86648

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

When an application uses one of the Microsoft Windows file functions

(_lclose, _lcreat, _llseek, _lopen, _lread, or _lwrite) and an error

occurs, the function returns the HFILE_ERROR error code. No additional

information is available concerning the cause of the error. Specifically,

no MS-DOS error return value is available for these functions.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


PRB: Creating File with Exclusive Access Allows Concurrent Use

Article ID: Q86723

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application calls the OpenFile() API and specifies the OF_CREATE

and OF_SHARE_EXCLUSIVE flags, the created file is not open for exclusive

access. Another application can also open the file.

RESOLUTION

==========

To create a file and open it for exclusive access, an application must

create the file, close the file, and open it for exclusive access.

MORE INFORMATION

================

OpenFile() passes its parameters to MS-DOS Interrupt 21h. OpenFile() and

Interrupt 21 exhibit the same behavior in this regard.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrFileIO


Creating Import Libraries with the __export Modifier

Article ID: Q88278

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The __export function modifier, widely advertised in version 7.0 of

the Microsoft C/C++ Optimizing Compiler, can be used in conjunction

with the /GD option switch to export a function from a dynamic-link

library (DLL) for the Microsoft Windows operating system without

listing the name of the function in the EXPORTS section of the DLL's

module definition (.DEF) file.

To create an import library for a DLL that uses this technique, the

filename of the DLL must be listed as a parameter to the IMPLIB

function. Otherwise, IMPLIB does not place the functions marked with

__export into the import library.

For more information on exporting functions, query on the following

words in the Microsoft Knowledge Base:

   __export and keyword and def and prolog

MORE INFORMATION

================

The first argument to the IMPLIB command is the name of the import

library to create. The second parameter is the name of the .DEF file,

the name of the .DLL file, or both. The syntax listed in the IMPLIB

online help file is as follows:

   IMPLIB [options] implibname {dllfile... | deffile...}

If a .DEF file is listed as the second parameter, IMPLIB places all

functions listed in the EXPORTS section into the import library. This

is the traditional method of creating a DLL import library and it

applies to versions of the Microsoft C Compiler prior to version 7.0.

If a DLL file is listed as the second parameter, IMPLIB places all

functions marked with the __export keyword in the DLL source code in

the import library. This method is required when the DLL source code

contains exported functions that are not listed in the .DEF file.

Otherwise, these functions would be excluded from the import library.

In addition, if the DLL is developed in C++, the names of exported

functions are generally not available to place in the .DEF file

because C++ decorates function names. To create an import library for

exported C++ functions, IMPLIB must read the function names from the

DLL.

To create an import library that contains only a subset of the

functions marked __export, create a .DEF file containing only the

names of the functions to include in the import library and specify

the name of the .DEF file as an argument to IMPLIB.

Note that any function that is marked with the __export keyword is

compiled with the default DLL export attributes in the import library.

To modify any of the attributes (for example, to add the NODATA or

RESIDENTNAME attributes to the exported function), you must list the

function name in the EXPORTS section of a .DEF file.

An example of a function that must be listed in the .DEF file is a WEP

(Windows exit procedure) function. Because the WEP must have the

RESIDENTNAME attribute, the following information must appear in the

EXPORTS section of the DLL's .DEF file:

   SEGMENTS 'WEP_TEXT' FIXED PRELOAD

   EXPORTS

      WEP  @1  RESIDENTNAME

The SEGMENTS declaration tells Windows to load the WEP_TEXT segment

into a fixed memory location as it loads the DLL into memory.

To place both the functions marked as __export and the WEP into the

import library, specify both the .DEF file and the .DLL file as

arguments to the IMPLIB command.

For more information on using Microsoft C/C++ 7.0 to create a WEP

function compatible with Windows 3.1, see pages 980 and 981 of the

Microsoft Windows Software Development Kit (SDK) "Programmer's

Reference, Volume 2: Functions" manual for version 3.1 and the

DETAILS.TXT file distributed with Microsoft C/C++.

For more information on using the /GD option switch with the __export

keyword, see page 515 of the Microsoft C/C++ "Environment and Tools"

manual for version 7.0, or query in the Microsoft Knowledge Base on

the word "/GD."

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Stack Traces Under Windows 3.1 SDK Debugging Kernel

Article ID: Q89331

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

When a FatalExit occurs, the Microsoft Windows operating system

version 3.1 Software Development Kit (SDK) debugging kernel does not

display a stack trace on the debugging monitor unless the user presses

the ENTER or SPACEBAR key immediately after the kernel displays the

"Abort, Break, Ignore" message. This behavior is different from that

found in the debugging kernel for Windows version 3.0 or prerelease

versions of Windows version 3.1.

The rationale behind changing this behavior was to simplify the

interface to the debugging kernel and to speed its execution. When a

FatalExit message occurs, a stack trace is available if desired.

However, the kernel does not take time to create and display unwanted

stack traces.

MORE INFORMATION

================

In its default configuration, the Windows debugging kernel displays

messages on a serial terminal connected to the COM1 port. The kernel

produces four levels of messages: Trace, Warning, Error, and

FatalExit. Appendix C of the SDK "Programming Tools" manual and the

SDK Help system documents the Windows debugging kernel.

When the debugging kernel displays the "Abort, Retry, Ignore" message

for a FatalExit it does not display a stack trace immediately.

Instead, the kernel enters a loop, waiting for the user to respond. If

the user presses the SPACEBAR or ENTER key before the loop times out,

the kernel displays the stack trace. To continue execution after the

stack trace, press the I key to ignore the FatalExit. The other

options are to press the A key to abort execution or the B key to

break into the debugger.

The Windows 3.1 SDK includes an advanced sample application called

DBWIN that provides a good user interface and some useful features to

assist in debugging a Windows-based application with the debugging kernel.

If the advanced samples are installed into the default directory, the

DBWIN source code is in the C:\WINDEV\SAMLES\DBWIN directory.

DBWIN can redirect debugging messages into a window on the main

display or to a secondary monochrome monitor. However, when DBWIN

redirects messages in this manner, the debugging kernel ignores

FatalExit messages (irrespective of the debug settings). In other

words, no stack traces are available when DBWIN redirects debug

messages to a window or a secondary monochrome monitor. However,

stack traces are available when DBWIN redirects debugging information

to COM1 or COM2 as outlined above for a debugging terminal.

DBWIN ignores FatalExit messages because the system runs much faster

when it displays debugging messages in a window rather than on a

serial terminal. However, because a stack trace provides very useful

information to assist in debugging an application, this default

behavior might not be considered very useful.

The text below provides the modification to the DBWIN source code

required to provide stack traces in a window or on a secondary

monochrome monitor. The modified version of DBWIN produces a stack

trace for every FatalExit message displayed by the debugging kernel,

similar to the behavior of the Windows 3.0 debugging kernel. While the

system might run slowly with the modified DBWIN, the additional

debugging information might make the change worthwhile. The modified

version of DBWIN is available in the NUDBWIN file in the Software/Data

Library.

Download NUDBWIN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for NUDBWIN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NUDBWIN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NUDBWIN.EXE

The only modifications required are to the NotifyCallback function in

the DBWINDLL.C source file. Add the text in the lines that begin with

NEW to the file, as follows:

BOOL CALLBACK _export _loadds NotifyCallback(WORD id, DWORD dwData)

{

    BOOL fHandled;

     .

     .

NEW // By default, produce stack trace at every FatalExit

NEW static BOOL fStackTrace = TRUE;

    // If we're not outputting anything,

    // just return FALSE to chain to next handler.

    if (modeOutput == OMD_NONE)

        return FALSE;

          .

          .

          .

    case NFY_INCHAR:

        switch (modeOutput)

        {

        case OMD_COM1:

        case OMD_COM2:

            fHandled = (BOOL)ComIn();

            break;

        default:

NEW         if (fStackTrace)

NEW            fHandled = (BOOL)' '; // Return a SPACEBAR press

NEW                                  // to produce stack trace

NEW         else

NEW            fHandled = (BOOL)'i'; // Return an I key press to

NEW                                  // ignore the FatalExit

NEW

NEW      // Do not produce the stack trace a second time at the

NEW      // "Abort, Break, Ignore" message. Ignore FatalExit this time

NEW      fStackTrace = !fStackTrace;

        }

        break;

          .

          .

          .

Additional reference words: 3.10 softlib NUDBWIN.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDebug


Creating Dynamic Code Segments Using PrestoChangoSelector

Article ID: Q89560

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Some problems arise when an application for the Microsoft Windows

graphical environment uses a segment addressed by a selector that is

not allocated by the Windows kernel. This article describes the

correct method of building selectors at run time. While the text below

describes the problems that arise when an application calls the

PrestoChangoSelector() function to alias a selector, it does not

discuss other difficulties involved in building a code segment at run

time. Note that the techniques in this article are specific to the

current implementation of 16-bit Windows.

Note that version 3.0 of the Windows Software Development Kit (SDK)

"Reference: Volume 1" manual refers to the PrestoChangoSelector()

function as the ChangeSelector() function.

MORE INFORMATION

================

If a callback function, for example, a window procedure, is located in

a dynamic code segment, the Windows user module encounters some

problems when any application exits because the selector for the

segment was not allocated by the kernel. To work around this problem,

the application must save the original selector used to access the

segment [obtained from the AllocSelector() function] and use the

original selector to execute the code in the segment [using

PrestoChangoSelector()]. The code fragment below demonstrates this

technique. Note that DATA_SELECTOR is a selector obtained from the

GlobalAlloc() function.

   WORD wCopyOfDataSelector;

   WORD wSelectorToCode;

   // When an application calls AllocSelector() with a valid selector,

   // the function copies the information associated with the selector

   // to a new location in the descriptor table used by Windows and

   // returns the new location. In the code below, wCopyOfDataSelector

   // is a second entry in the descriptor table that points to a

   // globally allocated block of memory.

   if ((wCopyOfDataSelector = AllocSelector(DATA_SELECTOR)))

      {

      // PrestoChangoSelector() toggles the bit in the descriptor table

      // that indicates whether the associated block of memory is code

      // or data. Therefore, in the code below, wSelectorToCode is a

      // code selector to the wCopyOfDataSelector (and DATA_SELECTOR)

      // block of memory.

      if ((wSelectorToCode = PrestoChangoSelector(DATA_SELECTOR,

                                                  DATA_SELECTOR)))

         {

         // Call code through wSelectorToCode

         // Read or write using wCopyOfDataSelector

         return TRUE; // Everything worked!

         }

      else

         return FALSE; // Changing the selector failed

      }

   else

      return FALSE;    // Unable to allocate selector

   // Be sure to free the allocated selector before the application

   // terminates.

   if (FreeSelector(wCopyOfDataSelector))

      return FALSE;  // Selector not freed

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Additional Documentation for GetDOSEnvironment()

Article ID: Q89568

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

Add the following comment to the documentation for GetDOSEnvironment() on

page 366 of the Microsoft Windows Software Development Kit (SDK)

"Programmer's Reference, Volume 2: Functions" manual:

   If the TEMP MS-DOS environment variable points to an invalid

   directory, the GetDOSEnvironment function removes the TEMP

   environment variable from the returned environment string and

   replaces its contents with "x" characters.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMisc


Using Large Memory Model, Microsoft C/C++, & Windows 3.1

Article ID: Q90294

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In Windows version 3.0, using the large memory model with Microsoft C

version 6.0 is not recommended. For more information on the problems

that occur when using the large memory model under Windows 3.0, query

this knowledge base on the following words:

   large and model and protected

Windows version 3.1 and the Microsoft C/C++ version 7.0 compiler have

resolved most of these problems and make the large memory model much

more suitable for developing applications under Windows 3.1.

MORE INFORMATION

================

There are three main problems when using the large memory model under

Windows:

1. Large model applications can have multiple data segments (this is

   always the case when compiling with Microsoft C 6.0). In Windows

   3.0, these extra segments are loaded as FIXED and page-locked.

   Having a large amount of FIXED page-locked memory results in a

   serious degradation of the memory manager's performance. FIXED

   memory is allocated from the bottom of the global heap, which means

   it normally lies in conventional memory (below 1 MB), which is

   needed by the Windows loader when it loads a new module into

   memory. For more information on this topic, query this knowledge

   base on the following words:

      using and memory and below and megabyte

   This problem has been corrected in Windows 3.1. In Windows 3.1, an

   application's code and data segments are always loaded as MOVEABLE,

   regardless of the segment attributes specified in the application's

   definition (.DEF) file. A DLL's code and data segments are loaded

   exactly as they are specified in the DLL's .DEF file.

2. Under both Windows 3.0 and Windows 3.1, only one instance of an

   application with multiple data segments can be run at one time.

   This is because the Windows loader can't fix-up multiple instances

   of a far pointer because code is shared among all instances of an

   application.

   In most cases, this problem may be resolved by using the /Gx and

   /Gt compile options with the Microsoft C/C++ 7.0 compiler. The /Gx

   option causes the compiler to force static data into the default

   data segment, which results in the application having only one data

   segment. Note, however, that this works only if the application's

   static data, string literals, stack, and heap all fit into a 64K

   segment.

   The /Gt switch specifies the size a static object must be to be

   allocated its own data segment. When trying to create a single data

   segment, this threshold value should be large enough to ensure

   that no data objects are allocated outside of the default data

   segment. If the /Gt option is not specified, the data threshold

   will be 32767.

3. The final problem with using large model under both Windows 3.0 and

   Windows 3.1 is the performance degradation that occurs when an

   application uses far pointers to access its data.

   When running under the protected mode of the Intel 286, 386, and

   486 processors, a far address is a combination of a selector and an

   offset. A selector is essentially an index into an array called a

   descriptor table. A descriptor is an 8-byte value that contains

   information about the segment, such as its base address, size,

   read/write privileges, and so forth.

   Whenever a far variable is referenced in protected mode, the

   processor must load the descriptor into one of the segment

   registers' descriptor cache and mark the descriptor as being

   accessed. This means that a reference to a far variable requires at

   least two reads from and one write to memory just to obtain the

   variable's linear address.

   Adding this delay to the time needed for performing far pointer

   arithmetic amounts to a significant loss of performance when

   compared to the medium model, which uses near pointers for data.

   One method to increase the performance of a large model application

   is to explicitly declare commonly used global or static variables

   as being NEAR, which causes the compiler to allocate the variable

   in the default data segment, and to use a near pointer when

   referencing the variable.

Conclusion

----------

Because Windows 3.1 and Microsoft C/C++ 7.0 have resolved most of the

problems related to use of the large memory model, developing

application for Windows 3.1 with the large memory model is much more

acceptable than it was under Windows 3.0 and Microsoft C 6.0.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrModls


Using OpenDriver() to Communicate Data to Installable Drv

Article ID: Q90562

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The lParam parameter supplied to the OpenDriver() call can be used to

communicate information from a Windows-based application or

dynamic-link library (DLL) to an installable driver. Windows resolves

the call to OpenDriver() to three subsequent calls to the DriverProc()

of the installable device driver; the third call calls the driver's

DriverProc() with the message set to DRV_OPEN and lParam2 set to the

lParam supplied to OpenDriver(). Thus, the DriverProc() could use the

lParam2 supplied to process instance-specific information.

One problem with this approach is that the control panel can call

OpenDriver() with lParam2 set to 0 (zero) if a control panel

application is being provided for that driver; thus, the DriverProc()

of the installable driver cannot expect this parameter to contain

valid communication values at all times.

MORE INFORMATION

================

To work around this problem, you should set aside a dedicated

initialization message greater than DRV_USER and call

SendDriverMessage() with that value as the message parameter after

calling OpenDriver() to open the installable device driver.

Note that because the hDriver parameter passed to DriverProc() is

unique with every call to OpenDriver(), you can associate instanced

data with each instance of the driver. Alternatively, the DRV_OPEN

switch in your DriverProc() could check whether lParam2 is 0 (zero)

and take action accordingly. This technique, however, bears the

potential problem that any application or DLL that erroneously opens

the driver with a nonzero lParam2 parameter can confuse the driver

significantly.

For multimedia drivers, MMSYSTEM.DLL takes a slightly different

approach to work around this problem. Aside from DriverProc(), each

multimedia driver must export a second message-processing function

called xxxMessage (where xxx is either of wod, wid, mod, mid, or aux,

respectively; depending on the type of driver). MMSYSTEM.DLL

broadcasts initialization messages to these respective functions upon

Windows boot time; the message parameters sent to the message

functions are labeled WODM_INIT, WIDM_INIT, MODM_INIT, MIDM_INIT, and

AUXM_INIT, respectively, and are provided for one-time initialization.

The xxxMessage functions cannot fail the xxxM_INIT messages; however,

MMSYSTEM.DLL will call the message processing functions with their

respective GETNUMDEVS messages immediately after sending the xxxM_INIT

messages; if it finds the return value of that call to be greater than

or equal to 0x10000 (in other words, if the HIWORD of the return value

is not equal to zero), it will abort loading the driver.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMisc


Terminating Windows-Based Application from Another App

Article ID: Q92528

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

An application can be cleanly terminated by another application by posting

WM_CLOSE to its top-level, non-owned, non-disabled windows. Disabled

windows should not be posted WM_CLOSE because they may be disabled as a

consequence of a modal dialog box being displayed or because they may be in

a state that does not allow termination. The Tool Helper library has a

function TerminateApp() to close an application. However, TerminateApp()

does not terminate an application cleanly and is designed to be used in a

debugging environment.

MORE INFORMATION

================

Clean termination means that an application terminates as designed by the

application designer after freeing its resources. Clean termination of a

Windows-based application by another Windows-based application is possible

in many cases by posting WM_CLOSE to top-level, non-owned, non-disabled

windows of the application. However clean termination is not possible in

some cases because of the following reasons.

If a Windows-based application has a modal dialog box displayed, it is in a

modal state. The transition out of the modal state takes place when the

modal dialog box is closed in a manner specified by the application

programmer -- typically when the user selects a dialog box button. If the

owner of a modal dialog box is posted WM_CLOSE, it will destroy the modal

dialog box by calling DestroyWindow(). This particular transition out of

the modal state may not have been designed by the application programmer

because modal dialog boxes are designed to be closed by EndDialog(), not

DestroyWindow(). Consequently, the dialog box could terminate without

cleaning up. For example, a dialog box that frees GDI objects when it

receives a WM_COMMAND with wParam == IDOK or IDCANCEL will not free these

objects if it is closed as a consequence of WM_CLOSE being posted to its

owner.

Clean termination is possible in the above case if the terminating

application expects to be closed as a consequence of the owner being posted

a WM_CLOSE while a modal dialog box is up. Note that most applications do

not expect to be closed in this way.

Algorithm to Terminate an Application

-------------------------------------

Obtain the handles of all top-level, non-owned windows of the application

that is to be terminated as described in a following section.

For each of the top-level, non-owned windows of an application:

{

  if (IsWindowEnabled(hwnd))

     PostMessage(hwnd, WM_CLOSE, 0, 0);

}

WM_CLOSE is posted only if the window is not disabled. A disabled window

could mean that it is the owner of a modal dialog box and so should not be

closed. A window is also disabled when an application does not want the

user to manipulate it (including closing it), and consequently should not

be closed.

A modal dialog box disables only its immediate owner. This means that a

top-level window that is not disabled, but that owns a window that in turn

owns a modal dialog box, can be closed and the dialog box can consequently

be destroyed. However, this can also be done by the user and so should have

been prevented by the application if it was not to be allowed.

Obtaining Handles of Top-Level, Non-Owned Windows of an Application

-------------------------------------------------------------------

1. EnumTaskWindows() can be used to enumerate all the top-level windows

   owned by the task. The task handle of the task required for this

   function can be obtained using the Tool Helper library functions and one

   of the following three methods:

   a. If the task to be terminated is started after the terminator task,

      the terminator can set up a call-back function using

      NotifyRegister(). This call-back function is called by every task in

      the system on start up and termination. GetCurrentTask() can be used

      to obtain the task handle of the task that called the call-back

      function. TaskFindHandle() can be used to obtain information about

      this task from a TASKENTRY structure.

      If the terminator task wants to terminate all the child tasks that it

      spawned using WinExec(), the following method can be used. A child

      task can be identified by checking whether the hTaskParent field in

      the TASKENTRY structure contains the terminator's task handle:

BOOL FAR PASCAL NotifyRegisterCallback (WORD wID, DWORD dwData)

{

    HTASK hTask;

    TASKENTRY te;

    switch (wID)

    {

       case NFY_STARTTASK:

       case NFY_EXITTASK:

          // Obtain info about the task that is starting/terminating.

          hTask = GetCurrentTask();

          te.dwSize = sizeof(TASKENTRY);

          TaskFindHandle(&te, hTask);

          // ghTaskParent is the task that called NotifyRegister().

          // Check if hTask is a child task of ghtaskParent.

          // ghwnd is a window of the parent task.

          if (te.hTaskParent == ghtaskParent)

             if (wID == NFY_STARTTASK)

                PostMessage(ghwnd, PM_TASKSTART, (WORD)hTask, 0);

             else

                PostMessage(ghwnd, PM_TASKEND, (WORD)hTask, 0);

          break;

       default:

           break;

    }

    // Pass notification to other callback functions.

    return FALSE;

}

      The parent task must maintain a list of child tasks that are

      currently running by adding a child task handle to the list when

      PM_TASKSTART is received and by removing a task handle when

      PM_TASKEND is received. The Task List, which is brought up by

      choosing the Switch To system menu item, and some screen savers, are

      run as child tasks of the active application. All child tasks can be

      terminated by calling EnumTaskWindows() on each of the task handles

      in the list. Below is the callback to EnumTaskWindows():

BOOL CALLBACK EnumTaskWindowsCallBack(HWND hwnd, LONG lParam)

{

   // Check whether the window still exists and that it does not have an

   // owner.

   if (IsWindow(hwnd) && !GetWindow(hwnd, GW_OWNER))

   {

      // Do not close disabled windows.

      if (!IsWindowEnabled(hwnd)))

         return TRUE;

      else

         PostMessage(hwnd, WM_CLOSE, 0, 0);

   }

   return TRUE;

}

      The TERMWAIT sample application, which can be found in the

      Software Library by searching on the keyword TERMWAIT,

      demonstrates the use of NotifyRegister().

   b. The Tool Helper library functions TaskFirst(), TaskNext(), and

      TaskFindHandle() and the szModule field in the TASKENTRY structure

      can be used to obtain the task handle if the Module name is known.

   c. If the window handle of one window belonging to a task is known, the

      handles to other top-level windows of the task can be obtained using

      GetWindowTask() and EnumTaskWindows().

2. Window handles can be obtained using FindWindow() if the window title or

   class name is known.

Additional reference words: 3.10 call back

KBCategory: kbprg

KBSubcategory: KrTskIns


GlobalReAlloc() and GMEM_ZEROINIT Clarified

Article ID: Q92942

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

GlobalReAlloc() is documented in the Windows API's reference manuals. This

is a clarification of one of the flags you can set for GlobalReAlloc().

Under one circumstance, when GlobalReAlloc() is used with GMEM_ZEROINIT, it

may not zero out all of the reallocated memory. This situation occurs when

GlobalReAlloc() is called to shrink a block of memory and then enlarge it.

MORE INFORMATION

================

When GlobalReAlloc() is used with GMEM_ZEROINIT to increase the size of a

block of memory in the global heap, it will zero out only the bytes it adds

to the memory object; it does not initialize any of the memory that existed

before the call.

Windows allocates memory from the global heap in multiples of 32 bytes;

enhanced mode allocates memory on even 32-byte boundaries, and standard

mode allocates memory on odd 32-byte boundaries (that is, /E allocates

32/64/96 bytes, /S allocates 16/48/80 bytes).Thus, when 10 bytes are

requested, enhanced Windows actually allocates 32 bytes; when 55 bytes are

requested, enhanced Windows allocates 64 bytes.

Suppose we have the following sequence of calls in Windows enhanced mode:

HGLOBAL hMem ;

      // 32 bytes are actually allocated, not 10 because Windows

      // allocates global memory in multiples of 32 bytes. All

      // 32 bytes are initialized to zero.

hMem = GlobalAlloc(GMEM_ZEROINIT | GMEM_FIXED, 10);

      // Here, we allocate 32 more bytes and add them to the end of

      // the first 32 bytes. ReAllocating to 40 bytes will cause the

      // block to be 64 bytes long. Only the second 32

      // bytes are initialized to zero. The first 32 bytes are left

      // alone.

hMem = GlobalReAlloc(hMem, 40, GMEM_ZEROINIT | GMEM_FIXED);

      // Copy 39 bytes into the memory block. The first 39 bytes

      // will contain the string.

lstrcpy((LPSTR)GlobalLock(hMem), "This is a big enough string for our job")

      // Now we shrink the block to 10 bytes. After the call, the

      // block will be 32 bytes long; the second 32 bytes are freed

      // and will no longer exist. The first 32 bytes will still

      // contain the same characters as before the call.

hMem = GlobalReAlloc(hMem, 10, GMEM_ZEROINIT | GMEM_FIXED) ;

      // Now, we enlarge the block back to 40 bytes.  After the call,

      // the block will be 64 bytes long, and the second 32 bytes

      // will be initialized to zero. The first 32 bytes will be left

      // alone, however. The area between bytes 10 and 32 does *not*

      // get initialized!

hMem = GlobalReAlloc(hMem, 40, GMEM_ZEROINIT | GMEM_FIXED) ;

When GlobalReAlloc() is called to shrink the block, we told it that we

wanted only 10 bytes; that's all we should use. Then when we enlarge it

back to 40 bytes, GlobalReAlloc() only initializes the memory it adds to

the current block--which is from bytes 33 to 64. The bytes between 10 and

40 were previously used, but GlobalReAlloc() did not initialize them

because it did not allocate them.

As a result, applications that call GlobalReAlloc() to shrink and then re-

enlarge a block of previously used data should not expect that all the

bytes will be initialized to zero.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Calling Int86?, Intdos?, and DOS3Call() from Windows

Article ID: Q93343

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Int86/Int86x and Intdos/Intdosx functions, which are part of the C Run-time

library, can be used to execute a documented MS-DOS-based software

interrupt. The Windows (application programming interface (API) DOS3Call()

also allows a Windows-based application to call an MS-DOS Interrupt 21h

(Int 21h) function. Under the Windows versions 3.x environment, it is

acceptable to call any of these functions from within an application or a

DLL (dynamic-link library). This article discusses certain issues involved

with using these functions in Windows.

NOTE: The Win32 "Programmer's Reference, Volume 1" manual states that

DOS3Call() (or any 80x86 specific interrupt call) is NOT supported, and

therefore an application that uses ANY of the above mentioned functions, by

definition, will not run under Windows NT.

MORE INFORMATION

================

There are certain issues that must be considered when calling any of the

above mentioned functions from within a Windows-based application or a DLL.

Some of these issues are listed below:

 - Both the Int86x and Intdosx functions copy the DS and ES register

   values from the SREGS structure to the CPU registers before issuing

   the software interrupt. It is important to initialize the DS and ES

   register values in the SREGS structure BEFORE calling int86x() and

   intdosx(). Normally this is done by calling the _segread() function

   or the _FP_SEG macro. Otherwise, a general protection (GP) fault

   may occur as a result of attempting to load invalid selector values

   into the DS and ES registers from uninitialized values in the SREGS

   structure.

 - Another issue is related to memory models, DLLs, and passing correct

   parameters to the int86/int86x and intdos/intdosx functions. These

   functions take, as parameters, pointers to structures and unions.

   Therefore, while using small or medium model, you must ensure that

   these objects are always in the automatic data segment or the

   DGROUP. Thus, in a DLL, these objects cannot be allocated from the

   stack, such as a local variable, because SS != DS in a DLL. In

   addition, in an application these objects cannot be allocated from

   the global heap using the global memory APIs or be declared as

   being FAR (which would put them in a different data segment than

   the DGROUP).

 - Executing the software interrupt, Interrupt 21h, directly from

   within Windows is not significantly slower than calling DOS3Call().

   Because this speed factor depends on the type of the CPU being

   used, it should not be considered a major factor in using either

   the DOS3Call() or Interrupt 21h call in Windows. Also, the speed

   factor is only an implementation issue and not a conceptual issue.

   For more information on issues related to compatibility,

   portability, and so forth, please query on the following words in

   the Microsoft Knowledge Base:

      low-level and interrupts and portability

 - Both standard mode MS-DOS extender and Windows enhanced mode provide

   translation services for most of the commonly used interrupts.

   However, when an application needs to communicate with a network, a

   TSR (terminate-and-stay-resident program), or any real mode

   software for which Windows does not provide automatic translation,

   it must use MS-DOS Protected Mode Interface (DPMI) services. For more

   information on the list of interrupts that are supported/translated

   by protected mode Windows or on DPMI, please query on the following

   words in the Microsoft Knowledge Base:

      dpmi and INTEL and 31h

   (NOTE: One of the articles incorrectly states that the Int 25h and

   Int 26h interrupts are not translated by Windows.)

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDosint


Virtual DMA Services (VDS) Application Note Available

Article ID: Q93470

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

In the MS-DOS environment, an application that performs direct memory

access (DMA) programs the hardware DMA controller with a memory buffer

address. However, in the Microsoft Windows environment, the application

cannot directly determine the buffer address. Therefore, Windows provides

the Virtual DMA Services (VDS) to provide the information required to

program the DMA controller.

An application note that describes the VDS is now available. Application

note PW0519 details the data structures and services required to implement

the VDS in a DMA device driver in the Windows environment.

Application note PW0519 is available in the Software/Data Library, through

the Microsoft Download Service (MSDL), or directly from Microsoft. In the

United States, application notes can be obtained by calling Microsoft

Product Support Services at (206) 454-2030. Outside the United States,

contact the Microsoft subsidiary or distributor that serves your country.

Download PW0519.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PW0519.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PW0519.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PW0519.EXE

Additional reference words: 3.00 3.10 appnote softlib PW0519.EXE

KBCategory: kbprg kbappnote kbfile

KBSubcategory: KrMm


Using GlobalDosAlloc() and GlobalDosFree()

Article ID: Q95545

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

GlobalDosAlloc() is used by Windows-based applications and dynamic-link

libraries (DLLs) to allocate memory blocks that are guaranteed to

exist in the first megabyte (MB) of linear address space.

GlobalDosFree() is used to free memory blocks allocated by

GlobalDosAlloc(). Memory blocks allocated by GlobalDosAlloc() are

fixed in standard mode and page locked in 386 enhanced mode.

Neither of these functions is prototyped in the Microsoft Windows

version 3.0 Software Development Kit's WINDOWS.H; however, both are

correctly prototyped in the Microsoft Windows version 3.1 SDK's

WINDOWS.H. Furthermore, both functions are prototyped incorrectly in

the Windows 3.0 SDK "Reference, Volume 1" and in the Windows 3.1 SDK

"Programmer's Reference, Volume 2: Functions." The correct prototypes

are:

   DWORD FAR PASCAL GlobalDosAlloc(DWORD cbAlloc);

   UINT FAR PASCAL GlobalDosFree (UINT uSelector);  // in Windows 3.1

   WORD FAR PASCAL GlobalDosFree (WORD wSelector);  // in Windows 3.0

The return value of GlobalDosAlloc(), if successful, contains a

selector in the low-order word and a paragraph-aligned segment value

in the high-order word. If GlobalDosAlloc() fails, it returns zero. If

GlobalDosFree() succeeds, it returns zero. If it fails,

GlobalDosFree() returns the value of the selector passed to it.

Memory below 1 MB is scarce and should not be allocated by

applications or DLLs unless absolutely necessary. For further

information about how memory below 1 MB is used, query on the

following words in the Microsoft Knowledge Base:

   GlobalDosAlloc() or memory

MORE INFORMATION

================

The following code sample demonstrates how to use GlobalDosAlloc() and

GlobalDosFree():

   DWORD dwMyLowMemory;

   UINT  uMySegment;

   UINT  uMySelector;

   LPSTR lpProtModePtr;

   DWORD lpRealModePtr;

    .

    .

    .

   if ((dwMyLowMemory = GlobalDosAlloc(512)) == 0)

      return FALSE;    // Error: unable to allocate memory

   // GlobalDosAlloc() allocates global memory that can be accessed by

   // real-mode applications. The memory is guaranteed to exist in the

   // first megabyte of linear address space.

   //

   // GlobalDosAlloc() returns a DWORD in which the high-order word is a

   // paragraph segment and the low-order word is a selector.

   uMySegment  = HIWORD(dwMyLowMemory);

   uMySelector = LOWORD(dwMyLowMemory);

   lpProtModePtr = (LPSTR)MAKELONG(0, uMySelector);

                                               // protected mode pointer

   lpRealModePtr = (DWORD)MAKELONG(0, uMySegment);

                                               // real mode pointer

    .

    .

    .

   if ((uMySelector = GlobalDosFree(uMySelector)) != NULL)

      return FALSE;    // Error: unable to free memory

This example works correctly in all Windows modes. The selector value

returned by GlobalDosAlloc() does not need to be locked via a call to

GlobalLock() because it is already locked. Because the value of

uMySegment is a paragraph-aligned segment value, the starting offset

of the memory object will be zero. In Windows 3.0 real mode,

GlobalDosAlloc() returns segment values in both words.

GlobalDosAlloc() allocates memory below 1 MB in linear address space. In

standard mode, this memory is in the first megabyte of physical memory

because linear addresses are the same as physical addresses. In 386

enhanced mode, however, linear addresses are not the same as physical

addresses. Memory allocated via GlobalDosAlloc() is not guaranteed to

reside in the first megabyte of physical memory nor to be physically

contiguous. Furthermore, because the physical address of a memory

block allocated via GlobalDosAlloc() is not known in 386 enhanced mode,

it is not suitable for DMA transfers or memory-mapped hardware.

In 386 enhanced mode Windows, GlobalDosAlloc() allocates memory blocks

in the Windows virtual machine only. Terminate-and-stay-resident

programs (TSRs) and MS-DOS device drivers that were started before

Windows are global to all virtual machines and thus can use these

memory blocks. However, TSRs and MS-DOS-based applications that are started

in Windows MS-DOS boxes run in their own virtual machines and so cannot

see the memory allocated by GlobalDosAlloc(). Because memory allocated

by GlobalDosAlloc() is not global to all virtual machines, it cannot

be used to communicate asynchronously (based on hardware interrupts,

for example) with TSRs. For examples of Windows-based applications that

communicate with TSRs, study the GDOSMEM and TDOSMEM sample

applications included in the Windows 3.1 SDK, or query on the

following words in the Microsoft Knowledge Base:

   GDOSMEM or TDOSMEM

If GlobalDosAlloc() is called from within a DLL, the allocated memory

block is owned by the application instance that called the DLL, not

the DLL. However, it is sometimes necessary for a DLL to own a block

of memory that MS-DOS can access. (For example, a DLL may need its own

buffer to communicate with a TSR.)

Because GlobalDosAlloc() doesn't take a parameter to specify the

attributes of the memory block to be allocated as GlobalAlloc does,

how can the memory be assigned to a DLL? The DLL can allocate the

memory on behalf of the calling application instance and then call

GlobalReAlloc() to change the ownership of the memory block to itself.

The following code sample demonstrates this technique:

   // Called from within a DLL

   HGLOBAL hMyLowMem;

   DWORD   dwMyLowMemory;

   UINT    uSelector;

   LPSTR   lpszProtModePtr;

    .

    .

    .

   if ((dwMyLowMemory = GlobalDosAlloc (512)) == 0)

      return (FALSE);      // Error: unable to allocate memory

   uSelector = LOWORD(dwMyLowMemory);

   lpszProtModePtr = (LPSTR)MAKELONG(0, uSelector);

   hMyLowMem = LOWORD(GlobalHandle (uSelector));

   hMyLowMem = GlobalReAlloc (hMyLowMem, 0, GMEM_MODIFY |

                                            GMEM_DDESHARE);

    .

    .

    .

After the call to GlobalReAlloc(), the memory block will belong to the

DLL and can be accessed by lpszProtModePtr. To free the memory block,

just call GlobalDosFree(); there is no need to change the ownership of

the block back to its original owner.

GlobalDosAlloc() and GlobalDosFree() are not the same as the DPMI DOS

Memory Management Services (functions 100h to 102h). Windows

applications and DLLs should not use these DPMI functions because

GlobalDosAlloc() and GlobalDosFree() perform the same functions.

Important note: Applications and DLLs should not use GlobalDosAlloc()

unless absolutely necessary because the free memory pool below 1 MB

from which it allocates is a scarce system resource.

GlobalDosAlloc() and GlobalDosFree() are documented on pages 4-236 and

4- 237 of the Microsoft Windows SDK 3.0 "Reference, Volume 1" and on

pages 501 and 502 of the Microsoft Windows SDK 3.1 "Programmer's

Reference, Volume 2: Functions."

Additional reference words: 3.00 3.10

KBCategory: kbprg kbcode

KBSubcategory: KrMm


Detecting Idle Time in Windows

Article ID: Q96422

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

When the system goes idle under Microsoft Windows version 3.1, Kernel

issues a single Interrupt 2Fh function 1689h call. This interrupt can be

used by a Windows-based application to detect idle time.

MORE INFORMATION

================

Listed as "Windows kernel idle call" in the INT2FAPI.INC file of the

Windows Device Development Kit (DDK) version 3.1, Interrupt 2Fh

function 1689h is the system-idle notification. To be notified when

the system becomes idle, a Windows-based application must put an interrupt

service routine (ISR) in the Interrupt 2Fh chain using the MS-DOS Set

Interrupt Vector call (Interrupt 21h function 25h), and look for AX

register equal to 1689h. The ISR must call the address of the old

handler to pass the control down the Interrupt 2Fh chain. The address

of the old handler can be retrieved using the MS-DOS Get Interrupt

Vector call (Interrupt 21h function 35h).

The ISR must be part of a device driver, dynamic-link library (DLL),

or installable device driver. Furthermore, the ISR is required to be

in a fixed segment. This can be accomplished by marking the segment of

the ISR as PRELOAD FIXED in the module definition (.DEF) file for the

DLL.

Hooking Interrupt 2Fh function 1689h to detect idle time can result in

performance degradation. Therefore, if a Windows-based application only

needs to perform background processing, it must use the PeekMessage()

and WaitMessage() functions. Only those applications that need to detect

idle time (for example, benchmarking applications) should use

Interrupt 2Fh.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMisc


Registering a Class in a DLL

Article ID: Q97758

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

If a class is registered in a dynamic-link library (DLL) with the

RegisterClass() function and an application uses this class when

creating a window or a dialog box, then the CreateDialog() or

CreateWindow() call in the application will fail. The debug version of

Windows will produce a Fatal Exit code 0x8800 with the following

message:

   CreateWindow failed:  Window class not found.

Either of the following may generate this message:

 - The window class in the DLL was not registered correctly with the

   CS_GLOBALCLASS class style. Without this class style, a class

   cannot be accessed globally by all the applications that link into

   the DLL.

   -or-

 - The DLL is not loaded into memory and therefore the class is not

   accessible. This will happen if the application implicitly links

   to the DLL, and none of the exported functions in the DLL is

   explicitly called in the application. To work around this problem,

   the DLL must provide an entry point for the application to call or

   the application must explicitly load and free the library.

MORE INFORMATION

================

To register a window class in a DLL and subsequently create a window

(or create a dialog box) of that class in any application that links

into this DLL, the window class must be registered with the

CS_GLOBALCLASS class style. This style specifies that the window class

is an application global class, and will allow this class to be

accessed globally by all applications. The CS_GLOBALCLASS class style

is documented in the Windows version 3.1 SDK "Programmer's Reference,

Volume 1: Overview," manual on page 19 under the Class Styles section.

Care must be taken to ensure that an application global class is not

accessed after the DLL (that registered it) terminates. Doing so will

generate a Fatal Exit 0x001A message under the debug version of

Windows. For more information on this topic, query on the following

words in the Microsoft Knowledge Base:

   fatal exit and 0x001A

After registering the window class using the CS_GLOBALCLASS class

style, calling CreateWindow or CreateDialog from an application should

work correctly. However, if the intent is to have the DLL own the

message queue, this is not possible. The reason is that DLLs, being

taskless entities, are designed to be resources or to only provide

resources and functions; they are not capable of handling the message

processing. This functionality must be implemented in an application.

Also, note that with Windows version 3.0, there is a potential problem

in destroying windows whose window class has been registered with the

CS_GLOBALCLASS class style by a DLL (or an application). This problem

has been corrected in Windows version 3.1. For more information on

this problem and a solution, please query on the following words in

the Microsoft Knowledge Base:

   exit and windows and DLL-instanced

Once the class is registered properly with the CS_GLOBALCLASS style in

the DLL, any application can use it, provided the DLL is loaded in

memory. This issue is of concern in cases where the DLL is used only

to register classes (for example, in LibMain) that can be used by all

applications (for example, custom control libraries). Because the DLL

does not contain any function entry points that the application can

call into, there are no call-dependencies between the application and

the DLL, and therefore the DLL will not be loaded implicitly. In such

a case, the solution is that the DLL must provide an entry point that

the application can call or the application must explicitly load and

free the library using LoadLibrary and FreeLibrary application

programming interfaces (APIs).

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


PRB: Error in the THSAMPLE Sample Application

Article ID: Q99335

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Windows version 3.1 Software Development Kit (SDK) provides a

sample called THSAMPLE, which is in the SDK subdirectory \SAMPLES\TOOLHELP.

This sample application uses the TOOLHELP.DLL to provide the type of

information that HEAPWALK shows.

SYMPTOMS

========

When the THSAMPLE sample application is run and the Enable List option is

enabled from the Notification menu, some of the notification messages are

not seen in the notification window.

This problem can be demonstrated, for example, by starting the Windows Help

application when the Enable List option is enabled in the THSAMPLE

application. (Note that it is preferable to turn off the task switch

notifications using the Notification/Task Switch Filter option).

CAUSE

=====

There is a simple error in the THSAMPLE application. THSAMPLE uses

NotifyRegister() to register a callback function that receives all

the notification messages. This callback function is then posting a

user-defined message to itself using PostMessage() for every

notification message it receives, and displaying it in the

appropriate window.

There is a default limit, however, of eight messages that an

application's message queue can hold, whereas the callback could

receive a lot more notifications (for example, when some

applications are started, a number of LOADSEG notifications are

sent).

RESOLUTION

==========

To correct this behavior, the application's message queue size

must be increased by using SetMessageQueue() set to an appropriate

number. Note that starting and exiting some applications such as

Windows Help, Word for Windows, or Excel will produce a large

number of LOADSEG and FREESEG notifications. Therefore, it is

better to set the message queue size to the maximum of 120 in order

to be able to look at most of the notifications.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: KrToolHlp


Chaining NotifyRegister Callbacks Issuing Notifications

Article ID: Q99671

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Microsoft Windows version 3.1 can register callback functions with the

NotifyRegister() application programming interface (API), which

is called on notifications. Callback functions that result in a

notification being issued, however, themselves fail to chain on to

other registered callbacks. This causes negative side-effects to other

applications that use NotifyRegister().

MORE INFORMATION

================

NotifyRegister() can install callback functions that are called in

response to events such as the starting and ending of an application,

the loading of a segment, the freeing of a module, and so forth. Only

one callback can be installed per task running in Windows. When more

than one task is running, each can install a notification callback.

Multiple callback functions are called by a chaining mechanism

implemented in TOOLHELP when an event occurs. Callback functions are

called in the order they were installed by the tasks. See the Windows

Software Development Kit (SDK) version 3.1 "Programmer's Reference,

Volume 2: Functions" manual for more information on NotifyRegister().

If a callback routine performs an operation that causes another

notification to be issued, then the callback functions are not called

in the usual chained manner. The problem is not that the callback

routine isn't handling reentrancy; rather, NotifyRegister() has not been

implemented to handle callbacks that result in notifications being

issued.

For example, a common procedure is to call OutputDebugString() to help

debug an application. However, callback functions installed by

NotifyRegister() cannot use OutputDebugString() because this API call

causes the NFY_OUTSTR notification to be issued. When OutputDebugString()

returns, TOOLHELP can't chain on to the next installed callback function.

The result is that only the first callback is called for the event at which

OutputDebugString() was called.

If printing debug messages from the callback routine is desired, call

PostMessage() to inform the application of the event, and call

OutputDebugString() from the application's window procedure instead of

calling it directly from the callback routine. Using PostMessage() is

necessary for the application to perform any operation, not just a

call to OutputDebugString(), which causes a notification event to occur.

Incidentally, the documentation states that "the notification callback

function cannot use any Windows function, with the exception of Tool

Helper functions and PostMessage.()"

Having this type of error in an installed NotifyRegister() callback results

in negative side-effects in other applications that use  NotifyRegister().

Microsoft Visual C++ version 1.0 uses TOOLHELP notifications as part of the

integrated development environment debugger. If any application is running

that has installed a callback that causes notifications to be issued,

calling OutputDebugString() for example, Visual C++ will not be able to

initiate debugging an application. Upon starting to debug, Visual C++

displays an error message in a dialog box stating:

   DEBUG ERROR: Could not load debuggee.  Unknown Error in

   Windows (-22)

Once the application uninstalls the errant callback routine, Visual C++ can

debug without this error.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrToolHlp


PRB: Using SetCommState() to Toggle DTR/RTS for Flow Control

Article ID: Q99861

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When SetCommState() is used to raise the DTR and RTS lines for hardware

flow control, the first several incoming characters may be lost.

CAUSE

=====

SetCommState() calls the communications driver's setcom function, which

calls $SETCOM. $SETCOM disables interrupts from the specified port by

clearing the UART's interrupt enable register (IER). After changing the

state of the UART and the DTR and RTS lines, $SETCOM delays while

interrupts from the UART are still disabled. In Windows 3.1, this delay is

approximately 200 milliseconds; in Windows 3.0, the delay is approximately

55 milliseconds. If the DTR and RTS lines are raised from low to high, any

characters that arrive before interrupts from the UART are enabled will be

lost.

RESOLUTION

==========

SetCommState() should not be used to toggle the states of the DTR and RTS

lines for hardware flow control.

Use EscapeCommFunction() to toggle the the states of the DTR and RTS lines

because it does not delay while interrupts are disabled.

Additional reference words: 3.00 3.10 comm

KBCategory: kbprg kbprb

KBSubcategory: KrCommapi


Accessing the Modem Status Register (MSR) in Windows

Article ID: Q101417

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------\*

SUMMARY

=======

In the Microsoft Windows graphical environment, versions 3.0 and 3.1

of the communications driver (COMM.DRV) do not provide the absolute

states of the following control lines:

   CTS     Clear To Send

   DSR     Data Set Ready

   RI      Ring Indicator

   RLSD    Receive Line Signal Detect; Carrier Detect (CD)

The RLSD signal is probably the most important (for modem software),

and is often necessary. This article provides a method to obtain this

information. Although this method is undocumented, it will be

supported in future versions of 16-bit Windows.

MORE INFORMATION

================

The Windows Software Development Kit (SDK) documentation indicates

that SetCommEventMask() can be used to determine the absolute state of

these signals, using the EV_CTSS, EV_DSRS, EV_RING, and EV_RLSDS

events. However, in all cases, the EV_* bits are OR'd into the EvtWord

without clearing the previous value of the EvtWord. If a modem status

register (MSR) bit has become set, it will not be cleared until

GetCommEventMask() is called. Therefore, if a bit is set, but then

changes state, the EvtWord will still indicate that it is set until

GetcommEventMask() is called. (Note, however, that EV_RLSDS will never

be set. This is a bug in the Windows versions 3.0 and 3.1 COMM.DRV.)

One way to obtain the state information is to read the Modem Status

Register directly from the Universal Asynchronous Receiver Transmitter

(UART). However, this method clears the delta bits of the MSR making

them unavailable to COMM.DRV. Therefore, DO NOT DO THIS!

This information can also be obtained from COMM.DRV. COMM.DRV

maintains an extended data control Block (DCB) called the DEB. Within

this structure is a field called the MSRShadow. This is a shadow

(copy) of the MSR on the UART.

The following code will provide direct access to the MSRShadow byte.

DO NOT MODIFY THIS LOCATION!

   #define COMM_MSRSHADOW 35

   #define MSR_CTS              0x10  /* Absolute CTS state in MSR  */

   #define MSR_DSR              0x20  /* Absolute DSR state in MSR  */

   #define MSR_RI               0x40  /* Absolute RI state in MSR   */

   #define MSR_RLSD             0x80  /* Absolute RLSD state in MSR */

   LPBYTE GetCommMSRShadow(short nCid)

   {

      /* Return far pointer to MSR shadow byte */

      return (((LPBYTE)SetCommEventMask(nCid, 0) + COMM_MSRSHADOW);

   } /* GetCommMSRShadow */

Once this pointer is available, it can be used as follows:

      lpMSRShadow = GetCommMSRShadow(nCid);

      bRLSD = (*lpMSRShadow) & MSR_RLSD;

      if (bRLSD)

          /** RLSD is high **/

      else

          /** RLSD is low **/

Althought this method is supported in a Win32-based application, you should

use GetCommModemStatus() instead.

Additional reference words: 3.00 3.10 DDKCOMM

KBCategory: kbprg

KBSubcategory: KrCommapi


The DCB Structure in Windows 3.1

Article ID: Q101419

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

The data control block (DCB) structure defines the control setting for

a serial communications device. OpenComm() and BuildCommDCB() both

initialize a DCB structure. However, there are many fields in the DCB

that cannot be changed using these procedures. These fields can be

updated directly, and these changes can be applied to the

communications port using SetCommState().

MORE INFORMATION

================

OpenComm() uses BuildCommDCB() with "COM1:9600, E, 7, 1" as the

lpszDef parameter to build a default DCB. OpenComm() internally calls

SetCommState() with this default DCB to set the initial state of the

communications port.

BuildCommDCB() can be used to initialize a DCB with certain settings.

This procedure takes a string in the same format as the MS-DOS mode

command for its lpszDef parameter. For example,

BuildCommDCB("COM1:9600, n, 8, 1", &myDCB) sets myDCB to have a baud

rate of 9600, no parity, 8-bit byte size, and 1 stop bit. This string

needs to contain only the COM port and baud rate; if the other values

are absent, they will default. The default settings are even parity,

byte size of 7, and 1 stop bit. SetCommState() must be called to put

the new DCB settings into effect.

SetCommState() takes a DCB as a parameter, and sets the port according

to all the parameters. A DCB can be initialized by calling

BuildCommDCB() or the current settings can be returned by calling

GetCommState(). In addition, the fields in the DCB can be modified

directly. After a DCB is changed, SetCommState() must be used to apply

the setting to the port.

Below is a summary of all the DCB fields. Each field has a description

of what happens in BuildCommDCB(). The information that follows

SetCommState() indicates how the DCB can be manipulated manually. That

DCB can then be used in the lpDCB parameter to SetCommState().

Id - The ID of the port. This is set by BuildCommDCB(), and is the

     same as the OpenComm() return value.

BaudRate - BuildCommDCB() - The baud rate is based on the first two

     characters in the baud rate position in the MS-DOS mode string. For

     example, "COM1:96,n,8,1" will set the baud rate to 9600. The only

     baud rates that can be set are 110, 150, 300, 600,1200, 2400,

     4800, 9600, and 19200. If none of these baud rates are used,

     BuildCommDCB() returns an error.

     SetCommState() - The BaudRate field can set any baud rate up to 57,600

     by either setting the BaudRate field in the DCB to one of the

     CBR_baudrate constants, or to any number greater than 2 and less

     than CBR_110. Numbers outside this range result in SetCommState()

     returning an IE_BAUDRATE error.

ByteSize - BuildCommDCB() - Specifying any number other than 7 or 8

     results in an error.

     SetCommState() - The byteSize field can be set to any number between

     4 and 8. Numbers outside this range result in SetCommState()

     returning an IE_BYTESIZE error.

Parity - BuildCommDCB - The parity can be set to "E" (even), "O"

     (odd), "N" (none), "M" (mark) or "S" (space).

     SetCommState() - The Parity field in the DCB can be set to NOPARITY,

     ODDPARITY, EVENPARITY, MARKPARITY, or SPACEPARITY. Other settings

     result in SetCommState() returning and IE_DEFAULT error.

StopBits - BuildCommDCB - Stop bits of 1 or 2 are accepted. Any other

     value (including 1.5) returns an error.

     SetCommDCB() - The StopBits field can be set to ONESTOPBIT,

     ONE5STOPBITS, or TWOSTOPBITS. Other settings result in

     SetCommState() returning an IE_DEFAULT error.

The time-out field, RlsTimeout, CtsTimeout, or DsrTimeout, enables

time-out checking if its value is anything other than zero. This

time-out checking occurs during WriteComm() regardless of any other

values in the DCB, including fOutxCtsFlow and fOutxDsrFlow. Specifying

INFINITE does not really enable infinite time-out. The value is set to

-1 (which is 65536), which makes the time-out approximately 65

seconds. If a time-out occurs, WriteComm() returns 0 (zero), and

GetCommError() returns a time-out error (CE_CTSTO, CE_DSRTO, or

CE_RLSDTO).

RlsTimeout - BuildCommDCB() - If the 6th parameter of the MS-DOS mode

     string is specified as P, then this time-out is infinite (set to

     -1). Any other value returns an error. If it is not specified, it

     defaults to (zero).

     SetCommDCB() - RlsTimeout can be set to IGNORE, INFINITE, or any

     number.

     This field is the amount of time, in milliseconds, to wait for

     RLSD (same as Carrier Detect) to become high, before copying any

     data to the transmit queue during WriteComm().

CtsTimeout - BuildCommDCB() - MS-DOS mode string translated exactly like

     RlsTimeout.

    SetCommDCB() - CtsTimeout can be set to IGNORE, INFINITE, or any

    number.

    This field is the amount of time, in milliseconds, to wait for

    CTS (Clear to Send) to become high before copying any data to the

    transmit queue during WriteComm().

DsrTimeout - BuildCommDCB() - MS-DOS mode string translated exactly like

    RlsTimeout.

    SetCommDCB() - DsrTimeout can be set to IGNORE, INFINITE, or any

    number.

    This field is the amount of time, in milliseconds, to wait for DSR

    (Data Set Ready) to become high before copying any data to the

    transmit queue during WriteComm().

    All of the following flags are set to 0 in BuildCommDCB(), except

    for fBinary, which is set to 1. Any of these can be set to 0 or 1

    before calling SetCommState().

    fBinary - If fBinary is set to zero, reception of the EofChar

        character indicates the end of the input stream. ReadComm()

        will not return any characters past EofChar. If any characters

        are received after EofChar, it will be treated as overflowing

        the receive queue (CE_RXOVER). The reception of EofChar is

        indicated in the COMSTAT status flag CSTF_EOF. If fBinary is

        set to one, the EofChar character has no special meaning.

    fRtsDisable - RTS flow control is used ONLY if fRtsDisable is set

        to 0, and fRtsFlow is set to one. Any other combination will

        disable RTS flow control.

        OpenComm() will set RTS high, and it will remain high unless

        RTS flow control is enabled or fRtsDisable is set.

           fRtsDisable        fRtsFlow         RTS state

           ---------------------------------------------

              0               0                 Set High

              0               1           RTS flow control enabled

              1               0                 Set low

              1               1                 Set low

        CloseComm() does not change the state of RTS or DTR,

        regardless of the state of the disable settings, but it drops

        them momentarily while closing the port.

        If RTS or DTR are not being used for flow control, they can be

        manipulated using EscapeCommFuntion().

    fDtrDisable - Used with fDtrFlow. Functions similar to

        fRtsDisable/fRtsFlow.

    fRtsflow - See fRtsDisable.

    fDtrflow - See fDtrDisable and fRtsDisable.

    fParity - Specifies whether parity checking is enabled. If this

        flag is set, parity checking is performed, and CE_RXPARITY

        errors are reported.

        ReadComm() will return a negative value if it encounters an

        error (such as a parity error). GetCommError()is used to

        retrieve and clear that error. To receive notification of a

        parity error, SetCommEventMask() can be used to enable EV_ERR

        events. GetCommEventMask() should be used to clear the event,

        however, GetCommError() must still be used to clear the error.

    fOutxCtsFlow - Specifies that CTS signal is to be monitored for

        output flow control. If this flag is set and CTS is turned

        off, output is suspended until CTS is again set.

        If the CtsTimeout field contains any value other than zero,

        WriteComm() will wait for CTS, regardless of the value of

        fOutxCtsFlow.

    fOutxDsrFlow - Specifies that DSR signal is to be monitored for

        output flow control. If this flag is set and DSR is turned

        off, output is suspended until DSR is again set.

        If the DsrTimeout field contains any value other than zero,

        WriteComm() will wait for DSR, regardless of the value of

        fOutxDsrFlow.

    fDummy - Reserved.

    fOutX - Specifies that X-on/X-off flow control is used during

        transmission. If this flag is set, transmission stops when the

        XoffChar is received and starts again when the XonChar is

        received.

        If transmission is waiting as a result of the X-off character

        being received, the CSTF_XOFFHOLD flag in the COMSTAT

        structure will be set.

    fInX - Specifies that X-on/X-off flow control is used during

        reception. If this flag is set, the XoffChar character is sent

        when the reception queue comes within XoffLim characters of

        being full and the XonChar character is sent when the

        reception queue comes within XonLim characters of being empty.

        If transmission is waiting as a result of the X-off character

        being transmitted, the CSTF_XOFFSENT flag is set in the

        COMSTAT structure.

    fPeChar - Specifies that characters received with parity errors

        are to be replaced with the character specified by PeChar.

    fNull - Specifies that received null character are to be

        discarded.

    fChEvt - Not actually used.

    fDummy2 - Reserved.

XonChar - BuildCommDCB() - Set to 0x11 (CTRL+Q) SetCommState() - Can

    be set to any character.

    This field is the X-on character for both transmit and receive.

    See fInX and fOutX.

XoffChar - BuildCommDCB() - Set to 0x13 (CTRL+S) SetCommState() - Can

    be set to any character.

    This field is the X-off character for both transmit and receive.

    See fInX and fOutX.

XonLim - BuildCommSCB() - Set to 10. SetCommState() - Can be set to

    any value.

    When the number of characters in the receive queue drops below

    this value, the X-on character is sent, if enabled, and DTR is

    set, if enabled. See fInX and fOutX.

XoffLim - BuildCommDCB() - Set to 10. SetCommState() - can be set to

    any value.

    When the number of characters in the receive queue exceeds this

    value, the X-off character is sent, if enabled, and DTR is

    dropped, if enabled. See fInX and fOutX.

PeChar - BuildCommDCB() - Set to 0. SetCommState() - Can be set to any

    character.

    Parity error replacement character. See fPeChar and fParity.

EofChar - BuildCommDCB() - Set to 0. SetCommState() - Can be set to

    any character.

    Character which specifies end of input. See fBinary.

EvtChar - BuildCommDCB() - Set to 0. SetCommState() - Can be set to

    any character.

    Specifies the value of the character to be used to signal an

    event. When this value is received, an EV_RXFLAG event will be

    generated. The fChEvt flag is not actually used. Use

    SetCommEventMask() to enable these events.

TxDelay - Not actually used.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrCommapi


Sharing Files with Windows for Workgroups Clients

Article ID: Q101421

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit version 3.1

 - Microsoft Windows for Workgroups version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Multiple applications, each running in Windows for Workgroups version

3.1 on different workstations, can share a file residing on a server

with full read-write access while simultaneously keeping the file

open. File region locking ensures that data integrity of the file is

not lost. The Windows for Workgroups network redirector caches file

I/O operations unless file locking is used. It will seem that Windows

for Workgroups clients are failing to write data unless the

applications lock file regions.

MORE INFORMATION

================

Opening a file with READ_WRITE access and using the OF_SHARE_DENY_NONE

file sharing flag is possible from more than one application each

running from a different workstation. Applications sharing a file from

a server must use the same file sharing flags. Keeping the file open

may be a necessary specification for networked database management

systems because it is more efficient to keep the file open than to

open and close the file for each file-access operation. However, not

all applications should be designed to keep the file open during the

use of a file.

To better understand file sharing, consider an application running on

Workstation A opening a file that resides on the disk of Server S. An

application running on Workstation B can also open the same file so

that each application is aware of the updates made to the file on

Server S if the file is opened with READ_WRITE access and the

OF_SHARE_DENY_NONE sharing flag.

To ensure that two or more applications do not access the shared file

in the same region at the same time, locking is used to create

exclusive access to a region of the file. File region locking by one

application causes failure of file I/O operations performed by other

applications sharing the file. The sharing component of Windows for

Workgroups, VSHARE.386, keeps track of the region that is locked and

fails the file I/O operation attempting to access the shared file,

including any portion of the locked region. This is very critical to

file sharing; if one application is writing information into a

location of a shared file at the same instance another application is

reading from the same location of the shared file, there is a loss of

data integrity.

In Windows for Workgroups, file I/O operations are redirected to the

server drive via the network redirector component, VREDIR.386 (in

enhanced mode) or WORKGRP.SYS (in standard mode). The network

redirector of Windows for Workgroups caches file I/O operations. The

redirector will disable the cache if file locking is enabled, and

therefore even if two applications are sharing files and are being

careful so that there is no file access concurrency, Windows for

Workgroups will still fail to perform the file I/O unless file locking

is used. One application reading from the file will not be reading the

latest updates from the application writing to the file or data will

not seem to be written to disk.

The following summarizes key points when implementing applications to

share files residing on a server for full read-write access.

 - Open the file with READ_WRITE access and OF_SHARE_DENY_NONE sharing

   flag.

 - Before reading or writing, lock the region of the file about to be

   accessed. Use _locking() from the Microsoft C Run-time library or

   MS-DOS Interrupt 21h function 5Ch to lock the file region.

 - Immediately following a read or a write, unlock the region. Use

   _locking() or Interrupt 21h function 5Ch to unlock the file region.

   For courtesy to other applications using the file, do not exclude the

   use of a file region for a long period of time. Lock the file region

   only during accessing (reading or writing).

 - If the lock fails, this means that some portion of the region of

   the file is locked by another application. The application is not

   allowed access to this region until the other application releases it

   by unlocking the region.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


The "Segment Load Failure" Error Message

Article ID: Q102640

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Running an application in the Microsoft Windows operating environment

may produce a system modal dialog box containing the following error

message:

   Segment Load Failure

The error occurs inconsistently due to the cached file handle

mechanism of Windows version 3.1.

MORE INFORMATION

================

During the life of a Windows-based application, Windows may need to load

discarded code or resource segments or LOADONCALL segments for the

first time. To load the segment, Windows uses file I/O functions to

read the information from the .EXE file. If Windows has any errors

opening the .EXE file, it will produce the error message:

   Segment Load Failure

The following are possible reasons opening the .EXE file fails, but this

list is not exhaustive:

 - The filename was changed, deleted, or otherwise corrupted since

   the application was first started.

 - The .EXE file resides on a shared drive and is opened exclusively or

   in compatibility mode by another workstation running the

   application.

 - The .EXE file resides on a shared drive and is opened exclusively or

   in compatibility mode by another application for some purpose other

   than running the .EXE.

 - The system has run out of available file handles.

The error message may occur inconsistently or not at all due to the

mechanism used by Windows for caching file handles. The .EXE file is

referred to by a file handle. By default, Windows caches 12 file

handles for the most recently used files. If Windows subsequently

opens more files than what the cache can hold, the cache closes the

least recently used file handles. The error does not occur if Windows

uses a cached file handle to refer to the file, but will occur if the

file handle is no longer in the cache.

The file handle cache is a system-wide mechanism and not a

per-application mechanism. The number of cached file handles can be

changed by the CachedFileHandles switch in the [boot] section of the

SYSTEM.INI file. For more information regarding CachedFileHandles, see

the SYSINI.WRI file in the Microsoft Windows Resource Kit.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


WEP and Link Error L2023 Export Imported

Article ID: Q102644

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

LINK error L2023 is caused by an incorrect library link order. The linker

resolves external references in order of appearance of the libraries,

choosing the first occurrence of a label. This error occurs when a dynamic-

link library (DLL) exports the routine Windows exit procedure (WEP) that

will be brought in from the C Run-time library static .OBJs, but the linker

finds another DLL's WEP in its .LIB file because it appears BEFORE the C

Run-time library.

It would be best if DLL import libraries didn't include the WEP. This is

possible by using the PRIVATE keyword in you .DEF file when exporting your

WEP. Or, edit the .LIB via the LIB.EXE utility to remove the WEP reference.

MORE INFORMATION

================

If the MFC libraries are used, they should be included before any other

libraries. As for the other libraries, the Windows libraries should be

included first (that is, LIBW, COMMDLG, SHELL, and so forth), the C Run-

time second (that is, xLIBCyW.LIB for applications or xDLLCyW.LIB for

DLLs), and any additional third-party libraries last (that is, your own or

other's .LIBs). For example, when linking a small model DLL that uses

another DLL's routines via an import library, the library order would be

"LIBW.LIB SDLLCEW.LIB OTHERDLL.LIB". The order should be changed only if a

DLL routine was to replace one of the routines in the Windows libraries or

CRT.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Callback Functions in Multiple Instance Applications

Article ID: Q102871

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

--------------------------------------------------------------------

The following are some requirements for callback functions in multiple

instance applications when compiling with Microsoft C version 7.0 or C

version 8.0 for protected-mode-only Win16:

 - Callback functions must be branded with the "__export" keyword. The

   compiler switches -GA -GEf force all far functions in a module to

   be __export. The optimum method is to add the __export keyword to

   the particular callback function and not use the -GEf switch.

   Example:

      BOOL CALLBACK __export CallBackProc

 - Callback functions called via MakeProcInstance() must load DS from

   the value in AX. Use the compiler switch -GA with the -GEa switch

   to generate prolog code to load DS from the value in AX on all

   __export functions. The default for -GA is load DS from SS, which

   is not a valid assumption in callbacks. The code when loaded into

   memory should have three NOPs instructions at __export function

   entry points. Check with your favorite debugger that can show

   mixed/asm view once the module is loaded into memory.

 - Callback functions must have an export record in the EXE header. The

   classic method is to list the function in the EXPORTS section of

   the module's .DEF file. The callback's module can be built with the

   - GA -GEe switches to place an export record in the .OBJ at compile

   time for all __export functions.

 - Callback functions must assume SS != DS, DS not loaded on function

   entry. Compile with -Aw memory model customizer to have correct

   code generated.

 - Callback functions must not call C Run-time library code contained

   in the application (xLIBCyW.LIB) libraries. They assume SS == DS.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


PRB: Passing Modified Environments to Child Processes

Article ID: Q102958

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

Your application causes a general protection (GP) fault when starting

to run under Windows.

CAUSE

=====

To provide a new environment for Windows-based applications, the

LoadModule() function must be used. LoadModule() is similar to the MS-DOS

Interrupt 21h Function 4Bh call, which uses a structure to find the new

environment.

The element "envseg" must be set to the selector of a memory block

that contains a correctly formatted environment block. The loader

makes a copy of this memory block for the child process inside

LoadModule(). This copy is formatted similar to an MS-DOS 2.x environment

block. It does not have the MS-DOS versions 3.x and later additional

information, such as the full pathname of the task, attached to the end. If

startup code (such as the Microsoft C run time earlier than C/C++ version

7.0) looks for this additional information, a general protection (GP) fault

will occur. If you are certain that the task started via LoadModule() does

not make this assumption, then it is safe to use it.

Another bug with LoadModule() is the ownership of the copied memory created

by the loader. It's set to that of the parent, and therefore it needs to

outlive the child or its environment block will be freed when the parent

terminates.

RESOLUTION

==========

If it's necessary to provide a modified environment to MS-DOS-based

applications, the supported technique is to use an MS-DOS batch file. The

batch file first sets the new environment settings and then starts the

MS-DOS-based application.

   SET FOOS=BALL

   DOSAPP

If the application being started is not a Windows-based application, the

.BAT file technique is the only supportable method.

MORE INFORMATION

================

Regarding using LoadModule(), below is sample code that passes the current

task's environment as envseg:

Sample Code

-----------

   typedef struct tagCMDSHOW

   {

     WORD wFirst;

     WORD wSecond;

   }

   CMDSHOW;

   typedef CMDSHOW FAR * LPCMDSHOW ;

   typedef struct tagPARAMETERBLOCK

   {

     WORD      wEnvSeg;

     LPSTR     lpCmdLine;

     LPCMDSHOW lpCmdShow;

     DWORD     dwUnused;

   }

   PARAMETERBLOCK;

   typedef PARAMETERBLOCK FAR * LPPARAMETERBLOCK ;

   CMDSHOW        CmdShow;

   PARAMETERBLOCK ParameterBlock;

   char           szCmdName[] = "TASKMAN.EXE";

   char           szCmdLine[] = "";

   ParameterBlock.wEnvSeg            = HIWORD(GetDosEnvironment());

   ParameterBlock.lpCmdLine          = szCmdLine;

   ParameterBlock.lpCmdShow          = &CmdShow;

   ParameterBlock.lpCmdShow->wFirst  = 2;

   ParameterBlock.lpCmdShow->wSecond = SW_SHOW;

   ParameterBlock.dwUnused           = NULL;

   LoadModule(szCmdName, &ParameterBlock);

Additional reference words: 3.10 spawn

KBCategory: kbprg kbprb kbcode

KBSubcategory: KrTsksIns


Use EV_RINGTE for Modem Ring Detection

Article ID: Q103637

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

Many communications applications need ring detection. The documentation for

SetCommState() indicates that EV_RING should be the event to set for this

purpose. However, the EV_RING bit does not work as expected; the EV_RINGTE

(ring indicator trailing edge) event should be used for ring detection.

The trailing edge of the ring indicator (RI) generates a modem status

register (MSR) interrupt, which in turn sets the EV_RINGTE bit. EV_RING is

set to the current status of RI. Because the interrupt does not occur until

RI changes from high to low, EV_RING almost always is low (except when it

happens to be high during another MSR interrupt).

The EV_RINGTE event is not referenced in the SetCommEventMask()

documentation; however, it is defined in WINDOWS.H, and will be supported

in future versions of 16-bit Windows.

NOTE: The information in this article applies to the 16-bit comm driver in

Windows 95 also.

EV_RING

-------

EV_RING is set when the ring indicator is detected high during Modem Status

Register (MSR) interrupt processing. This is an absoulte state, but since

it is read only during MSR interrupt processing, it will almost always be

zero. The only time it will not be zero is when the ring indicator is high

and the MSR interrupt is triggered for some other reason, such as a change

in the state of a line (CD, CTS, or DSR). Because of this, EV_RING has no

real value for detecting a ring.

EV_RINGTE

---------

EV_RINGTE is set when a ring is detected on the modem. The trailing edge of

a ring indicator generates an MSR interrupt, which in turn sets the

EV_RINGTE event. Use this event to detect a ring.

Additional reference words: 3.10 Win16 COMM SetCommState event

KBCategory: kbprg kbdocerr

KBSubcategory: KrCommApi


SetSelectorLimit() Crossing 1 Megabyte Boundary

Article ID: Q103950

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

--------------------------------------------------------------------

SUMMARY

=======

The SetSelectorLimit() application programming interface (API)

function will not properly modify the limit of a selector if the

change is to cross the 1 megabyte (MB) (0x100000) boundary. That is,

the change is improper going from less than 1 MB to greater than 1 MB

and visa versa. In these cases, DPMI function 08h must be used to

properly change the limit of a selector.

MORE INFORMATION

================

SetSelectorLimit() does not correctly handle setting segment sizes

from less than 1 MB to greater than 1 MB because it will not set the

granularity bit. The granularity bit needs to be set to indicate page

granularity in the segment descriptor. When the granularity bit is

set, the selector limit has the form xxxxxFFFh for page alignment. A

page is 4K (4096 bytes).

Similarly, SetSelectorLimit() does not correctly handle setting

segment sizes from greater than 1 MB to less than 1 MB because it will

not clear the granularity bit. When the granularity bit is clear, the

selector limit has the form xxxxxh for byte alignment.

DPMI function 08h properly sets or clears the granularity bit when

appropriate. The limit must be in the form xxxxxFFFh when changed to

greater than 1 MB, and must be in the form xxxxxh when changed to less

than 1 MB.

Sample Code

-----------

//********************************************************************

// DPMISetSelectorLimit()

//

// Set a selector limit using DPMI Function AX=0008h Set Segment Limit

// This is necessary if the segment size is greater than 1 MB because

// SetSelectorLimit() does not correctly handle setting selector

// sizes greater than 1 MB.

//

// If the segment size is greater than 1 MB, it must be page-aligned

// or this function will fail. Segments sizes greater than 1 MB have

// a page granularity. Note that this function takes a segment limit

// that is one less than the number of bytes in the segment. If the

// segment size is greater than 1 MB, the segment limit should have

// the form xxxxxFFFh to be page-aligned.

//

//********************************************************************

BOOL DPMISetSelectorLimit (UINT selector, DWORD dwLimit)

{

    BOOL bRetVal=TRUE;

    _asm

    {

        mov  ax, 0008h

        mov  bx, selector

        mov  cx, word ptr [dwLimit+2]

        mov  dx, word ptr [dwLimit]

        int  31h

        jnc  success

        mov  bRetVal, FALSE

    success:

    }

    return bRetVal;

}

Additional reference words: gp-fault gpf uae gp fault

KBCategory: kbprg

KBSubcategory: KrMm


How OF_SHARE Modes Affect Opening Files

Article ID: Q104498

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

The following modes used when opening a file with OpenFile() have an effect

only if SHARE is loaded:

OF_SHARE_COMPAT (same as specifying no sharing flags, thus its name):

If the file has not been opened in any other sharing mode, the current

task may open the same file in OF_SHARE_COMPAT mode any number of

times. If the current task attempts to open the file in any other

sharing mode, the open will fail. If other tasks attempt to open the

file with any sharing mode, the open will fail. If the file has the

read-only file attribute, other tasks may open the file in

OF_SHARE_COMPAT mode any number of times.

OF_SHARE_DENY_WRITE: If the file has not been opened in any other

sharing mode, any task may open the file any number of times in

OF_SHARE_DENY WRITE. Attempting to open the file in any other sharing

modes will fail.

OF_SHARE_DENY_READ: If the file has not been opened in any other

sharing mode, any task may open the file any number of times in

OF_SHARE_DENY_READ. Attempting to open the file in any other sharing

modes will fail.

OF_SHARE_EXCLUSIVE: If the file has not been opened in any other

sharing mode, the file will be opened. Any additional attempts to open

the file in any sharing modes by any task will fail.

OF_SHARE_DENY_NONE: If the file has not been opened in any other

sharing mode, any task may open the file any number of times in

OF_SHARE_DENY_NONE. Attempting to open the file in any other sharing

modes will fail.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrFileIO


Using Int 21h Get/Set Media ID in the Windows Environment

Article ID: Q104790

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

SUMMARY

=======

The Interrupt 21h Generic IOCTL for Block Devices functions Get Media

ID and Set Media ID cannot be used directly from a protected mode

application in the Windows operating environment. However, these

functions can be used in conjunction with the DPMI function Simulate

Real Mode Interrupt.

MORE INFORMATION

================

The following Interrupt 21h AX=440Dh Generic IOCTL for Block Devices

functions are automatically translated from protected mode by the

DOSMGR VxD:

   40h - Set Device Parameters

   41h - Write Track on Logical Drive

   42h - Format Track on Logical Drive

   60h - Get Device Parameters

   61h - Read Track on Logical Drive

   62h - Verify Track on Logical Drive

   68h - Sense Media Type

The following are not automatically translated by the DOSMGR VxD:

   46h - Set Media ID

   66h - Get Media ID

To use the Get Media ID or Set Media ID functions from a protected

mode application in the Windows operating environment, the DPMI

function Simulate Real Mode Interrupt must be used to manually

translate the buffer pointer from protected mode to real mode.

The sample code below illustrates how the Get Media ID function can be

manually translated by:

1. Allocating a real mode addressable buffer using GlobalDosAlloc().

2. Initializing a DPMI real mode register structure with a real mode

   pointer to the buffer.

3. Issuing the interrupt in real mode using the DPMI function Simulate

   Real Mode Interrupt.

4. If successful, the content of the real mode addressable buffer is

   copied to the protected mode destination buffer.

5. The real mode addressable buffer is freed.

To translate the Set Media ID function, the contents of the protected

mode source buffer would be copied to the real mode addressable buffer

before issuing the interrupt in real mode.

Sample Code

-----------

// This is a standard MS-DOS structure.

typedef struct tagMEDIAID

{

    WORD  wInfoLevel;

    DWORD dwSerialNum;     // Serial number

    char  VolLabel[11];    // ASCII volume label

    char  FileSysType[8];  // File system type

} MEDIAID, far *LPMEDIAID;

// This is a standard DPMI structure.

typedef struct tagREALMODEREG {

    DWORD rmEDI, rmESI, rmEBP, Reserved, rmEBX, rmEDX, rmECX, rmEAX;

    WORD  rmCPUFlags, rmES, rmDS, rmFS, rmGS, rmIP, rmCS, rmSP, rmSS;

} REALMODEREG, FAR *LPREALMODEREG;

//********************************************************************

// RealInt()

//

// Simulate an interrupt in real mode using DPMI function 0300h

// When the interrupt is simulated in real mode, the registers will

// contain the values in lpRealModeReg. When the interrupt returns,

// lpRealModeReg will contain the values from real mode.

//

//********************************************************************

BOOL RealInt (BYTE intnum, LPREALMODEREG lpRealModeReg)

{

   BOOL bRetVal = TRUE;

   _asm

   {

       mov  ax, 0300h  // Simulate real mode interrupt

       mov  bl, intnum // Interrupt number to simulate

       mov  bh, 0      // Flags

       mov  cx, 0      // Number of words to copy on stack

       les  di, lpRealModeReg

       int  31h

       jnc  Done

       mov  bRetVal, FALSE

   Done:

   }

   return bRetVal;

}

//********************************************************************

// GetMediaID()

//

// Get Media ID by simulating an Interrupt 21h, AX=440Dh, CX=0866h in

// real mode. Set up RealModeReg to contain a real mode pointer to a

// MediaID structure.

//********************************************************************

BOOL GetMediaID (WORD      Drive,

                 LPMEDIAID lpMediaID)

{

   REALMODEREG RealModeReg;

   DWORD       dwGlobalDosBuffer;

   LPMEDIAID   lpRMMediaID;

   BOOL        bRetVal;

   // (1) Get a real mode addressable buffer for the MediaID structure.

   //

   dwGlobalDosBuffer = GlobalDosAlloc(sizeof(MEDIAID));

   if (dwGlobalDosBuffer == NULL)

   {

       return FALSE;

   }

   // (2) Initialize the real mode register structure.

   //

   memset(&RealModeReg, 0, sizeof(RealModeReg));

   (WORD)RealModeReg.rmEAX = 0x440D;  // IOCTL for Block Device

   (WORD)RealModeReg.rmEBX = Drive;   // 0 = default, 1 = A, 2 = B

   (WORD)RealModeReg.rmECX = 0x0866;  // Get Media ID

   // Set the real mode DS:DX to a real mode pointer to the buffer.

   // The offset in DX is zero from the memset().

   RealModeReg.rmDS  = HIWORD(dwGlobalDosBuffer);

   // (3) Simulate the real mode interrupt.

   //

   if (RealInt(0x21, &RealModeReg) &&         // Int simulation ok?

       (RealModeReg.rmCPUFlags & 0x0001)==0)  // Carry clear?

   {

       // (4) Copy the content of the real mode addressable buffer

       //     to the protected mode destination buffer.

       //

       lpRMMediaID = (LPMEDIAID) MAKELP(LOWORD(dwGlobalDosBuffer), 0);

       *lpMediaID = *lpRMMediaID;  // Structure copy

       bRetVal = TRUE;

   }

   else

   {

       bRetVal = FALSE;

   }

   // (5) Free the real mode addressable buffer.

   //

   GlobalDosFree(LOWORD(dwGlobalDosBuffer));

   return bRetVal;

}

For more information on the DOS Protected Mode Interface (DPMI), see

the DPMI version 0.9 specification, which is available on the

Microsoft Developer Network CD Disk Four.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDosint


Explanation of Exporting Functions in Windows

Article ID: Q105137

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

SUMMARY

=======

Exporting functions under Windows is one of the least understood but

most important concepts to understand. If string constants are garbage

or global variables contain the wrong information, then exported

functions are probably not doing their job. Exported functions simply

establish the correct data segment (DS) value on function entry.

MORE INFORMATION

================

Function entry point code, referred to as "prolog" code, does the work

of setting up all the registers on function entry. Exported prolog

code works with the Windows loader to support all the different

techniques of establishing DS. There are three types of exported

prolog code: loading DS from the value in AX, loading DS from the

value in SS, and loading DS from a hard-coded value fixed up by the

loader. The first two techniques are used in applications, the last is

used by dynamic-link libraries.

Loading DS from the Value in AX

-------------------------------

This is the classic application exporting technique. This works with

the MakeProcInstance function, which loads the correct DS value into

AX before calling the exported function's prolog code. As an

application is loaded, all exported functions built with the -Gw

switch or -GA -GEa pair are modified so that the first 3 bytes of

prolog code are NOPs. The following prolog code sets up the stack

frame and finally loads DS from the value in AX. In mixed mode, it

would appear as follows:

  {

     nop

     nop

     nop

     push   bp

     mov    bp,sp

     push   ds

     mov    ds,ax

Loading DS from the Value in SS

-------------------------------

This is a more recent technique that assumes that the SS register

contains the correct DS value on function entry. For applications that

don't switch their stack segment nor are called from other

applications, this is a valid assumption. The -GA default code loads

DS from the value in SS without the loader required to fix up the

prolog code. In mixed mode, it would appear as follows:

  {

     mov    ax,ss

     push   bp

     mov    bp,sp

     push   ds

     mov    ds,ax

Loading DS from a Hard-Coded Value

----------------------------------

This is the classic dynamic-link library exported function prolog

code. Because libraries are single instance, it's possible to get away

with hard-coded values to establish DS. As a library is loaded, all

exported functions built with -Gw or -GD are fixed up to load DS from

a hard-coded value. In mixed mode, it appears as follows:

  {

     mov    ax,????

     push   bp

     mov    bp,sp

     push   ds

     mov    ds,ax

In the two techniques that involve the loader, an EXPDEF record must

appear in the EXE header for the exported function. This can be done

by the classic EXPORTS statement in the module definition file (.DEF)

or via the -GEe compiler switch. At a minimum, the newer switches

require the __export keyword to brand exported functions at compile

time or the -GEf switch (which brands all far functions as __export).

An example of the use of the __export keyword is as follows:

   void CALLBACK __export TheExportedFunction()

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrTsksIns


PRB: KRNL386: Unable to Enter Protected Mode

Article ID: Q105207

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

Windows 3.1 fails to boot and returns to MS-DOS with a "KRNL386: Unable to

enter Protected Mode" error message. This usually occurs after switching to

the debug version of Windows.

CAUSE

=====

Windows 3.1 was started with old files left over from an upgraded

installation of Windows 3.0 with the Windows 3.0 Software Development Kit

(SDK).

RESOLUTION

==========

Replace the old files with the correct versions. The files of importance

are KRNL386.*, KRNL286.*, GDI.*, and USER.*. The old files are from 1990

and the new files are from 1992. Sort by date, and replace these old files

with the correct versions.

MORE INFORMATION

================

It's generally a good idea to start with a fresh installation of Windows in

a clean directory when this problem occurs. This ensures that other

obsolete files are cleared from the upgraded 3.0 installation.

Additional reference words: 3.10

KBCategory: kbsetup kbprb

KBSubcategory: KrDebug


Solving the "Insufficient Memory to Run" Situation

Article ID: Q105274

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

Each task under Windows requires a data structure allocated below 1

megabyte (MB) called the Task Data Base (TDB). Under the debug version

of Windows, failure of a TDB's allocation shows up as:

   t Kernel: GlobalAlloc(200) failed for ????

This error occurs within the context of LoadModule as it attempts to

start a new task under a low conventional memory condition.

The most common cause of low conventional memory is fixed allocations

made on behalf of a dynamic-link library (DLL). Fixed allocations

should be used only for code and data touched at interrupt time. All

other allocations should be made with the moveable attribute.

MORE INFORMATION

================

The Windows heap consists of all conventional and XMS memory available

after WIN.COM and WIN386.EXE/DOSX.EXE are loaded by MS-DOS. These two

physically separate blocks are combined into a single linear address

space to make up the global heap.

Windows allocates fixed objects with a bottom up/first fit algorithm.

As more fixed objects are allocated from the heap, conventional memory

gets pinched. Eventually, even a small allocation for the TDB fails

resulting in LoadModule returning 0 (zero).

The HEAPWALK.EXE utility provides a view onto the global heap to

determine what is using up conventional memory. The Sort Address menu

item sorts the main heap with lower addresses at the top of the list.

Any object with an address of 9FFFF or below is in conventional

memory. An object with an "F" set in the FLG column is fixed. Any

fixed object owned by an application or its dependent dynamic-link

libraries that is not a TDB (TYPE Task in HEAPWALK) should be

considered suspect.

The module definition (.DEF) file should mark CODE MOVEABLE

DISCARDABLE and DATA MOVEABLE. Any allocations should contain the

GMEM_MOVEABLE attribute. The EXEHDR.EXE utility can be used to

indentify modules that use the fixed attribute for their code or data

segments. Segments without the <moveable> attribute in the "flags"

column of EXEHDR's output are fixed.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMm


How to Determine Drive Types in Windows

Article ID: Q105922

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Windows versions 3.0 and 3.1 GetDriveType() function is useful for

determining whether a given drive is on a network or uses fixed or

removable media, but does not determine the specific type of device

that is associated with the drive. This article presents a function,

GetDriveTypeEx(), that can determine whether a given drive exists and

whether it is one of the following types of devices:

   Hard disk drive

   RAM disk drive

   CD-ROM drive

   Floppy disk drive

   Remote network drive

   Other removable media drive (such as a Bernoulli box)

The function prototype for GetDriveTypeEx() is:

   UINT GetDriveTypeEx(int nDrive);  // 0=A, 1=B, 2=C, etc.

The return value of GetDriveTypeEx() is one of the following

constants:

   EX_DRIVE_REMOVABLE       EX_DRIVE_FIXED

   EX_DRIVE_REMOTE          EX_DRIVE_CDROM

   EX_DRIVE_FLOPPY          EX_DRIVE_RAMDISK

   EX_DRIVE_INVALID

IMPORTANT NOTE: GetDriveTypeEx() is designed only for 16-bit applications

and dynamic-link libraries (DLLs) for Windows; it will not work in 32-bit

applications or DLLs written for the Win32 application programming

interface (API).

The Windows 32-bit API version of the GetDriveType() function determines

whether a drive is a RAM disk or a CD-ROM in addition to categorizing the

drive as either removable media, fixed media, or remote. See the Microsoft

Win32 SDK for further information about how to use GetDriveType() in Win32

applications and DLLs.

MORE INFORMATION

================

GetDriveTypeEx() works by first calling the Windows GetDriveType() function

to categorize the drive as being either fixed, removable, remote (network),

or not present. If the drive is remote, it could be either a CD-ROM drive

or a network drive because CD-ROM drives are mapped by the MS-DOS network

redirector. The best way to determine whether a drive is a CD-ROM drive is

to call the Microsoft CD-ROM Extensions (MSCDEX) CD-ROM Drive Check

function.

If the drive uses fixed media, it could be either a hard disk or a RAM

disk. A good way to determine whether the drive is a hard disk is to

call the MS-DOS Get Device Parameters IOCTL function and then check

the device type byte in the returned structure. If the drive is not a

hard disk, it can be assumed to be a RAM disk because these are the

only two fixed media devices.

Finally, if the drive uses removable media, it could be a floppy disk

drive or some other device, such as a Bernoulli box. The MS-DOS Get

Device Parameters IOCTL function can be used to determine whether the

drive is a floppy disk drive; if it is not, it could be a Bernoulli

box or some other less common device.

The following code for Microsoft C compilers implements GetDriveTypeEx()

and its support functions and all required structures:

Sample Code

-----------

#include <windows.h>

#include <string.h>

   // Return values of GetDriveTypeEx().

#define EX_DRIVE_INVALID    0

#define EX_DRIVE_REMOVABLE  1

#define EX_DRIVE_FIXED      2

#define EX_DRIVE_REMOTE     3

#define EX_DRIVE_CDROM      4

#define EX_DRIVE_FLOPPY     5

#define EX_DRIVE_RAMDISK    6

   // See the "MS-DOS Programmer's Reference" for further information

   // about this structure.

typedef struct tagDEVICEPARAMS

   {

   BYTE  bSpecFunc;        // Special functions

   BYTE  bDevType;         // Device type

   WORD  wDevAttr;         // Device attributes

   WORD  wCylinders;       // Number of cylinders

   BYTE  bMediaType;       // Media type

                        // Beginning of BIOS parameter block (BPB)

   WORD  wBytesPerSec;     // Bytes per sector

   BYTE  bSecPerClust;     // Sectors per cluster

   WORD  wResSectors;      // Number of reserved sectors

   BYTE  bFATs;            // Number of FATs

   WORD  wRootDirEnts;     // Number of root-directory entries

   WORD  wSectors;         // Total number of sectors

   BYTE  bMedia;           // Media descriptor

   WORD  wFATsecs;         // Number of sectors per FAT

   WORD  wSecPerTrack;     // Number of sectors per track

   WORD  wHeads;           // Number of heads

   DWORD dwHiddenSecs;     // Number of hidden sectors

   DWORD dwHugeSectors;    // Number of sectors if wSectors == 0

                        // End of BIOS parameter block (BPB)

   } DEVICEPARAMS, FAR * LPDEVICEPARAMS;

   // Function prototypes

BOOL GetDeviceParameters (int nDrive, LPDEVICEPARAMS dp);

BOOL IsCDRomDrive (int nDrive);

UINT GetDriveTypeEx (int nDrive);

//-----------------------------------------------------------------

// GetDeviceParameters()

//

// Fills a DEVICEPARAMS struct with info about the given drive.

// Calls DOS IOCTL Get Device Parameters (440Dh, 60h) function.

//

// Parameters

//   nDrive   Drive number  0 = A, 1 = B, 2 = C, and so on.

//   dp       Pointer to a structure that will contain the drive's

//            parameters.

//

// Returns TRUE if it succeeded, FALSE if it failed.

//-----------------------------------------------------------------

BOOL GetDeviceParameters (int nDrive, LPDEVICEPARAMS dp)

   {

   BOOL bResult = TRUE;      // Assume success

   __asm {

         push ds

         mov  bx, nDrive

         inc  bx           // Convert 0-based #'s to 1-based #s

         mov  ch, 08h      // Device category--must be 08h

         mov  cl, 60h      // MS-DOS IOCTL Get Device Parameters

         lds  dx, dp

         mov  ax, 440Dh

         int  21h

         jnc  gdp_done     // CF SET if error

         mov  bResult, FALSE

      gdp_done:

         pop  ds

         }

   return (bResult);

   }

//-----------------------------------------------------------------

// IsCDRomDrive()

//

// Determines if a drive is a CD-ROM. Calls MSCDEX and checks

// that MSCDEX is loaded, and that MSCDEX reports the drive is a

// CD-ROM.

//

// Parameters

//    nDrive    Drive number  0 = A, 1 = B, 2 = C, and so forth.

//

// Returns TRUE if nDrive is a CD-ROM drive, FALSE if it isn't.

//-----------------------------------------------------------------

BOOL IsCDRomDrive (int nDrive)

   {

   BOOL bResult = FALSE;      // Assume not a CD-ROM drive

   __asm {

         mov  ax, 150Bh       // MSCDEX CD-ROM Drive Check

         xor  bx, bx

         mov  cx, nDrive

         int  2Fh

         cmp  bx, 0ADADh      // Check MSCDEX signature

         jne  not_cd_drive

         or   ax, ax          // Check the drive type

         jz   not_cd_drive    // 0 (zero) means not CD-ROM

         mov  bResult, TRUE

      not_cd_drive:

         }

   return (bResult);

   }

//-----------------------------------------------------------------

// GetDriveTypeEx()

//

// Determines the type of a drive. Calls Windows's GetDriveType

// to determine if a drive is valid, fixed, remote, or removeable,

// then breaks down these categories further to specific device

// types.

//

// Parameters

//    nDrive    Drive number  0 = A, 1 = B, 2 = C, etc.

//

// Returns one of:

//    EX_DRIVE_INVALID         -- Drive not detected

//    EX_DRIVE_REMOVABLE       -- Unknown removable-media type drive

//    EX_DRIVE_FIXED           -- Hard disk drive

//    EX_DRIVE_REMOTE          -- Remote drive on a network

//    EX_DRIVE_CDROM           -- CD-ROM drive

//    EX_DRIVE_FLOPPY          -- Floppy disk drive

//    EX_DRIVE_RAMDISK         -- RAM disk

//-----------------------------------------------------------------

UINT GetDriveTypeEx (int nDrive)

   {

   DEVICEPARAMS dp;

   UINT uType;

   _fmemset (&dp, 0, sizeof(dp));    // Init device params struct

   uType = GetDriveType (nDrive);

   switch (uType)

      {

      case DRIVE_REMOTE:

            // GetDriveType() reports CD-ROMs as Remote drives. Need

            // to see if the drive is a CD-ROM or a network drive.

         if (IsCDRomDrive (nDrive))

            return (EX_DRIVE_CDROM);

         else

            return (EX_DRIVE_REMOTE);

         break;

      case DRIVE_REMOVABLE:

            // Check for a floppy disk drive. If it isn't, then we

            // don't know what kind of removable media it is.

            // For example, could be a Bernoulli box or something new...

         if (GetDeviceParameters (nDrive, &dp))

            switch (dp.bDevType)

               {

                  // Floppy disk drive types

               case 0x0: case 0x1: case 0x2: case 0x3:

               case 0x4: case 0x7: case 0x8:

                  return (EX_DRIVE_FLOPPY);

               }

         return (EX_DRIVE_REMOVABLE);  // Unknown removable media type

         break;

      case DRIVE_FIXED:

            // GetDeviceParameters returns a device type of 0x05 for

            // hard disks. Because hard disks and RAM disks are the two

            // types of fixed-media drives, we assume that any fixed-

            // media drive that isn't a hard disk is a RAM disk.

         if (GetDeviceParameters (nDrive, &dp) && dp.bDevType == 0x05)

            return (EX_DRIVE_FIXED);

         else

            return (EX_DRIVE_RAMDISK);

         break;

      }

   return (EX_DRIVE_INVALID);   // Drive is invalid if we get here.

   }

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDsk


Determining the Stack Size of an Application

Article ID: Q107172

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The tool helper library (TOOLHELP.DLL) contains application programming

interface (API) functions that provide information about the task header of

a Windows-based application's default data segment (DGROUP). A Windows-

based application can use this information to determine the maximum stack

size, the optimum stack size for the application, and whether the stack is

going to overflow.

Because the tool helper library is redistributable, this information

applies to Windows 3.0 also.

MORE INFORMATION

================

A Windows-based application's DGROUP consists of several parts: the task

header, initialized and uninitialized static data area, stack, local

heap, and an atom table. The following picture extracted from Chapter

18 of the "Windows 3.1 Power Programming Techniques" by Peter Norton

and Paul Yao, shows the organization of the DGROUP:

                   ---------------

                  |               |

                  |               |

                  |  Local Heap   |

                  |               |

                   --------------- <-

                  |               |  |

                  |               |  |

                  |    Stack      |<-|-

                  |               |  | |

                   --------------- <-|-|-

                  |               |  | | |

                  |               |  | | |

                  |  Static Data  |  | | |

                  |               |  | | |

               --> ---------------   | | |

              |   | pStackBottom  |--  | |

              |    ---------------     | |

              |   | pStackMin     |----  |

              |    ---------------       |

   Task   ----|   | pStackTop     |------

   Header     |    ---------------

              |   |     .         |

              |   |     .         |

              |   |     .         |

               --> ---------------

The task header is a data structure stored in the first 16 bytes of

the DGROUP and contains information about the stack, the local heap,

and the atom table. Windows stores three variables (pStackTop,

pStackBottom, and pStackMin) that point to various places in the stack

as shown in the picture above. pStackTop and pStackBottom point to the

top and bottom of the stack, and these two values stay constant once

initialized. pStackMin changes during run time to indicate how much of

the stack is actually used. Given this information, the following can

be determined:

   Maximum Stack size = pStackBottom - pStackTop

   Dynamic Stack Size = pStackBottom - pStackMin

The maximum stack size is either the size specified in the DEF file

with the STACKSIZE statement or 5K (Windows provides a minimum of 5K

stack). Because Windows updates the pStackMin at run time, monitoring

the dynamic size gives an indication as to how much stack space an

application really needs. This value may also be used to check for

stack overflows during run time, although using stack probes is

definitely a better method for checking stack overflows. Some advanced

debuggers such as WDEB386 (included in the Microsoft Windows SDK) and

SoftIce/W (from NuMega Technologies, Inc.) allow breakpoints to be set

on particular memory locations; for example, if a breakpoint is set at

the bottom of the stack, the debugger will break just before a stack

overflow.

Windows-based applications can obtain the values of pStackTop,

pStackBottom, and pStackMin by calling the tool help library API functions,

which return a TASKENTRY structure. An application should call

GetCurrentTask() to get its task handle and then call TaskFindHandle(),

TaskFirst() or TaskNext() with the task handle as a parameter. The

TASKENTRY structure contains three members wStackTop, wStackBottom, and

wStackMinimum, which correspond to the three pointers pStackTop,

pStackBottom, and pStackMin, respectively.

CodeView for Windows (CVW) debugger can also be used to look at the

task header of an application's DGROUP. For example, using CVW one can

periodically check the first 16 bytes in the DGROUP using the command:

   D DS:0

CVW will then display the following information:

   DS:0006  PLOCALHEAP

   DS:0008  pAtomTable

   DS:000A  pStackTop

   DS:000C  pStackMin

   DS:000E  pStackBot

The three values pStackTop, pStackMin, and pStackBot at locations

DS:000A, DS:000C, and DS:000E, respectively, can be used to determine

information about the application's stack as illustrated above.

Additional reference words: 3.10

KBCategory: kbprg

KBSubCategory: KrMm


PRB: Not Enough Space for Environment

Article ID: Q107174

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

SYMPTOMS

========

When a Windows-based application is started, it fails to load. While

running under the debug version of Windows, one or both of the following

debug messages are displayed on the debug terminal:

   LocalAlloc Failed

   -or-

   GlobalAlloc Failed

Then, Windows generates the following unrecoverable application error

(UAE): "Not enough space for Environment."

CAUSE

=====

The initial size specified for the application's local heap in the DEF

file is too small to contain the local allocation for the environment.

RESOLUTION

==========

When the Windows loader loads an application, it also stores a copy of

the MS-DOS environment strings (such as the PATH string, and so forth)

in the application's DGROUP. In general, the space needed to store

this environment table could be around 200 to 300 bytes, but it could

vary depending on the environment variables in the system. The loader

will try to allocate space for the environment table using

LocalAlloc(), and this call will fail if there is not enough space in

the local heap. In such a case, Windows automatically tries to expand

the local heap by doing a Gloabal(Re)Alloc. Because the maximum size

for the DGROUP is 64K, the GlobalAlloc will fail if the loader tries

to grow the DGROUP beyond the 64K limit. This will happen when the

size of the DGROUP is close to the limit of 64K and there is not

enough space in the application's DGROUP for Windows to expand the

local heap in it. In such a case, the application's DGROUP must be

cleaned up to allow more space for the local heap. A few ways to do

this are:

 - Reduce the application's stack size using the STACKSIZE statement in

   the DEF file. A recommended stack size is between 5K and 10K. You

   can also determine exactly how much stack space your application

   needs and use that optimized value in your DEF file. For more

   information, query in the Microsoft Knowledge Base on the following

   words:

      stack pStackMin

 - Move string constants from your DGROUP into string tables in a DEF

   file. Move large static arrays from your DGROUP to dynamically

   allocated memory using GlobalAlloc.

 - If Microsoft C/C++ or Visual C++ compiler is being used, some of the

   data from the DGROUP can be moved into an extra data segment by

   using the /Gt compiler option (refer to pages 522-523 of the

   Microsoft C/C++ "Environment and Tools" manual). However, note that

   an application with multiple data segments will be restricted to

   only one instance. For more information on this problem, please

   query in the Microsoft Knowledge Base on the following words:

      large model C/C++

Additional reference words: 3.10 gpf gp-fault gp fault

KBCategory: kbprg kbprb

KBSubCategory: KrDebug


Using DebugOutput to Debug a Windows-Based Application

Article ID: Q107691

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

The DebugOutput() API has been added to Windows version 3.1. A Windows-

based application can use this function to send a message to a debugging

terminal connected to the COM1 port or to a window by using DBWIN. In the

16-bit Windows SDK, DBWIN is a sample application installed in the samples

directory (by default, C:\WINDEV\SAMPLES\DBWIN directory). DBWIN is also a

sample in Visual C++ for Windows. In the Win32 SDK for Windows NT 3.5 and

Windows 95, DBWIN is located in MSTOOLS\BIN.

NOTE: The DebugOutput() function works only under the debug version of

Windows. However, there are certain issues that must be considered while

using this function.

MORE INFORMATION

================

1. DebugOutput() is present only in the debugging version of Windows. The

   retail version of Windows contains a stub function at this entry point.

   While an application won't fail if it calls this stub function, the stub

   won't produce any output on the debug terminal. Before starting the

   debug version of Windows and using DebugOutput(), certain issues must be

   considered. For example, add the following lines to the [Windows]

   section of the WIN.INI file

      DebugOptions=0X0000

      DebugFilter=0X0000

      DebugTaskFilter=                  ; leave it blank

   and add the following new section to your SYSTEM.INI file:

      [Debug]

      OutputTo=NUL

   The setting for the OutputTo entry in the SYSTEM.INI file disables the

   default debug kernel output to the AUX device (which maps to the COM1

   port). This setting is recommended because the DBWIN Windows sample

   application can be used to redirect output to either COM1 or COM2.

   The setting for the DebugOptions entry corresponds to the value for the

   dwOptions member of the WINDEBUGINFO structure in the Windows SDK. The

   setting for the DebugFilter entry corresponds to the value for the

   dwFilter member of WINDEBUGINFO. To determine the proper hexadecimal

   value for a setting, add the values of the options to be set. For

   example, to specify DBO_CHECKHEAP and DBO_FREEFILL, the setting for the

   DebugOptions entry would be 0x0021 (0x0001 plus 0x0020). For information

   about the possible values for these options and a full description of

   the WINDEBUGINFO structure, see the Microsoft Windows SDK "Programmer's

   Reference, Volume 3: Messages, Structures, and Macros."

2. The DebugOutput() function is prototyped in the WINDOWS.H header file

   provided with the Windows SDK; however, it is not listed in the

   LIBW.LIB import library. Therefore, a Windows-based application that

   uses the DebugOutput function must import the function in the

   application's module definition (DEF) file. Add the following lines to

   the DEF file to import the DebugOutput function:

      IMPORTS

         _DebugOutput = KERNEL._DebugOutput

   The leading underscore in the function name and the capitalization of

   the name are important because the DebugOutput function is declared

   using the C calling convention.

3. The Windows SDK documentation states that the DBF_TRACE flag can be used

   to supply trace information when an error occurs. This information may

   be useful in debugging an application. However, the DBF_TRACE flag does

   not work by itself; this flag must be OR'ed with another flag,

   typically the DBF_APPLICATION flag. For example, the following works:

      DebugOutput( DBF_TRACE | DBF_APPLICATION, "This is a trace

      message.");

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrDebug


"Backward Compatibility Hack Enabled" Warning

Article ID: Q107692

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

The debug version of Windows that comes with the Windows SDK version 3.1

produces the following warning message:

   wn Kernel: Backward compatibility hack enabled: xxxxx

This warning message is related to the information in the [Compatibility]

section in the WIN.INI file that the USER and GDI modules use for backward

compatibility with Windows 3.0. That is, if your application is compiled

for 3.1 only, it will not be affected by the [Compatibility] section, and

therefore the above warning message will not be generated.

Suppose that a Windows-based application is compiled to be compatible with

both Windows versions 3.0 and 3.1 by using the /30 switch on the Resource

Compiler (that is, rc /30). Then, the above warning message will be

generated only when the application's module name matches with one of the

module names in the [Compatibility] section of the WIN.INI file.

To avoid this warning message, make sure that your application's name is

different from the ones in the [Compatibility] section, or do not resource

compile with the /30 switch.

Information regarding the purpose of the [Compatibility] section for a

listed application in the WIN.INI file and the identity of the application

is confidential to Microsoft.

Additional reference words: ini 3.10

KBCategory: kbprg

KBSubcategory: KrDebug


PRB: Share Buffer Exceeded

Article ID: Q107694

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0

---------------------------------------------------------------------

SYMPTOMS

========

In a Windows-based application, if calling SetHandleCount(x) to increase

the current task's file handle table to be able to open "x" number of

files, even though the call returned success, "x" number of files still

cannot be opened. Instead, the MS-DOS error 0x24 is encountered:

   Sharing Buffer Exceeded

CAUSE

=====

The MS-DOS error 0x24 "Sharing Buffer Exceeded" occurs because of the MS-

DOS SHARE (SHARE.EXE) utility. SHARE maintains a table containing the fully

qualified pathname, plus 11 bytes, of each open file in the system. By

default, the size of this table when the SHARE utility gets loaded is only

2048 bytes. When SHARE runs out of this buffer while opening a file, the

above error message is displayed.

RESOLUTION

==========

Increase the default size of the internal buffer that SHARE uses via the

/F:nnnn command-line argument to SHARE.EXE. Then, a Windows-based

application should be able to open more files at one time. The SHARE

utility is documented both in the MS-DOS "User's Guide" and the MS-DOS

"User's Reference" manuals. For example, adding the following line in the

AUTOEXEC.BAT file will set share's internal buffer size to 10,000 bytes.

   C:\DOS\SHARE.EXE /F:10000

Additional reference words: 3.10 sft 36

KBCategory: kbprg kbprb

KBSubcategory: KrFileIO


Using More Than Four Communications Ports in Windows

Article ID: Q108314

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

In theory, it is possible to use more than four communications (COM) ports

in a Windows-based application. In practice, however, due to the limitation

imposed by the Windows 3.1 communications (comm) driver, only a maximum of

four communications ports can be used.

MORE INFORMATION

================

The virtual communications device (VCD) under Windows can support up to

nine communications ports. And, the Windows communications functions also

support the use of nine communications ports in a Windows-based

application. All this information might indicate that a maximum of nine COM

ports can be used in a Windows-based application.

But the communications driver (COMM.DRV) that is shipped with Windows

version 3.1 supports a maximum of only four communications ports. For

example, you can use the following code in a Windows-based application:

   // Get the number of COM ports.

   nPorts = EscapeCommFunction(0,GETMAXCOM)+1;

Note, nPorts is not an indication of the number of communications ports

that the computer has; it indicates the maximum number of communications

ports the communications driver supports. For the Windows version 3.1

standard communications driver, nPorts is always four.

This situation might change in the future. For example, the communications

driver that ships with Windows for Workgroups version 3.11 does support

more than four communications ports. Also, some of the third-party

communications drivers, such as TurboCom by Pacific CommWare, do support up

to nine communications ports. For more information, contact:

   Pacific CommWare

   180 Beacon Hill Lane

   Ashland, OR 97520

   Voice: (503) 482-2744

   Fax: (503) 482-2627

   BBS: (503) 482-2633

Note that Microsoft does not recommend any third-party applications for a

given purpose. TurboCom is an example only. For more information on third-

party applications, please refer to discussions in the appropriate forums

on CompuServe or other bulletin boards.

Also, because the Windows Device Driver Kit (DDK) version 3.1 provides the

source code to all the drivers including the Windows standard

communications driver, one could modify the source code to provide support

for more than four communications ports under Windows. However, note that

modifying the communications driver source code is not a trivial operation.

For more information on how to modify the Windows communications driver

source code to provide support for nine communications ports, query the

Knowledge Base on the words:

   modifying comm nine

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrCommapi


Setting Baud Rates in Windows 3.1

Article ID: Q108928

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

Under Windows 3.1, baud rates are specified in the BaudRate field of the

communications port's DCB structure, and are set using SetCommState(). Baud

rates can be specified by using the CBR_ constants listed in WINDOWS.H, or

by using the actual baud rate.

MORE INFORMATION

================

OpenComm(), by default, sets the baud rate of a communications port to

9600. BuildCommDCB() can be used to set the baud rate; however,

BuildCommDCB() accepts only the following baud rates: 110, 150, 300, 600,

1200, 2400, 4800, 9600, and 19200. If none of these baud rates are used,

BuildCommDCB() returns an error.

The SetCommState() function can be used to set the baud rate to values

between 2 and 115,200. The following CBR_ constants are defined in

WINDOWS.H:

   CBR_110        CBR_14400

   CBR_300        CBR_19200

   CBR_600        CBR_38400

   CBR_1200       CBR_56000

   CBR_2400       CBR_128000

   CBR_4800       CBR_256000

   CBR_9600

NOTE: These are not the same constants as a listed in the Windows 3.1 SDK

documentation for the DCB structure.

NOTE: The CBR_56000 constant actually corresponds to a baud rate of 57,600.

NOTE: The baud rate divisor is incorrect for CBR_14400. For more

information, please see the following article in the Microsoft Knowledge

Base:

   ARTICLE-ID: Q83232

   TITLE     : BUG: Data Errors on 14400 Baud Serial Communications

SetCommState() allows either the CBR_ constant or the actual baud rate in

the BaudRate field of the DCB. SetCommState() calls into COMM.DRV to apply

the DCB settings to the communications port. Although CBR_128000 and

CBR_256000 are defined, they are not used in the communications driver

(COMM.DRV).

When setting the baud rate, COMM.DRV first determines if the baud rate is a

CBR_ constant; if so, COMM.DRV looks up the baud rate divisor in a table.

If the baud rate is not in the CBR_ constant table and the UART is 8250,

16540, or 16550, the baud rate is set using 115,200 as the divisor and is

divided by the user specified baud rate. The subsequent integer value from

this division is used to set the baud rate (the remainder from the division

is not used). For example, if the user specified a baud rate of 60000, the

calculation would be 115200/60000, which is 1.

Therefore, the baud rate can be set to 115,200 by placing any value in

BaudRate that is greater than CBR_56000 (57,600) and less than CBR_110,

because this will always equal a baud rate of 1 (using the above formula)

and signal the UART to operate at it's highest possible speed (115,200). A

115,200 baud rate cannot be specified directly in the DCB structure because

the baud rate variable is an unsigned integer and cannot be larger than 64k

in the 16 bit world.

Third-party replacement communications drivers may set baud rates

differently. If using a replacement, check with the software manufacturer

to determine how to correctly set the baud rate.

Additional reference words: 3.10 CBR_128000 CBR_256000 COMM.DRV

KBCategory: kbprg

KBSubcategory: KrCommapi


Suppressing "Cannot Find MYDLL.DLL" Error Box

Article ID: Q111610

-----------------------------------------------------------------------

The information is this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

-----------------------------------------------------------------------

SUMMARY

=======

When explicitly loading a dynamic-link library (DLL) using LoadLibrary(),

Windows will display a "file error" message box with the error

   Cannot find MYDLL.DLL

where MYDLL.DLL is the name of the DLL specified in LoadLibrary() before

returning from LoadLibrary() if the DLL does not exist in the Windows path.

For more information about the Windows path, see the Windows search order

described in the documentation for LoadLibrary().

It is possible to suppress this error message so that a custom error

message or other error handling may be implemented without this system

error box. To do so, call SetErrorMode() with SEM_NOOPENFILEERRORBOX before

the call to LoadLibrary(). LoadLibrary() will return error code 2 meaning

"File was not found."

MORE INFORMATION

================

SetErrorMode() only affects the error mode of the current task and does not

affect the entire system. The return value may be used to toggle the error

mode in different portions of an application.

For an implicitly loaded DLL that may be missing, the system will display

the aforementioned error box if the application is run from Program

Manager. After clicking the OK button, the following message appears:

   Cannot find file d:\path\myexe.exe (or one of its components).

   Check to ensure the path and filename are correct and that

   all required libraries are available.

From File Manager, no "file error" message box appears, but the following

message is displayed instead:

   File manager cannot find the specified file (or one of its

   components).

   Make sure the path and filename are correct and that all required

   libraries are available.

Because these error messages appear before the WinMain() of the application

executes, SetErrorMode() cannot suppress the error message boxes for

implicitly linked DLLs. Furthermore, there is no way to configure Program

Manager to suppress the "file error" message box.

Sample Code

-----------

 {

 HINSTANCE hDLL;

 UINT uOldErrorMode;

 uOldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);

 // Try to load DLL.

 hDLL = LoadLibrary("MYDLL.DLL");

 if (hDLL == 2)

    MessageBox(NULL, "MYDLL.DLL does not exist", "ERROR", MB_OK);

 else if (hDLL <= HINSTANCE_ERROR)

    MessageBox(NULL, "Other problems loading MYDLL.DLL, "ERROR", MB_OK);

 else

 {

    MessageBox(NULL, "MYDLL.DLL exists", "SUCCESS", MB_OK);

    FreeLibrary(hDLL);

 }

 SetErrorMode(uOldErrorMode);  // Can restore error mode if desired.

 }

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: KrDll


GETBASEIRQ EscapeCommFunction()

Article ID: Q112388

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

By calling EscapeCommFunction() with GETBASEIRQ as the nFunction parameter,

an application can determine the base I/O port address and IRQ used for a

specific communications port.

MORE INFORMATION

================

Although GETBASEIRQ is not documented in the Windows 3.1 SDK manuals, it is

listed in the WINDOWS.H header file, and will continue to be supported in

future versions of 16-bit Windows.

When calling EscapeCommFunction() with GETBASEIRQ, the value returned is a

LONG. The HIWORD of the return value is the IRQ and the LOWORD is the base

I/O address of the communications port.

Please note that this function call does not indicate whether a UART exists

at the port; it only returns the I/O base and IRQ that COMM.DRV would use

for that port.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrCommapi


WEPs, Windows, and Microsoft Visual C/C++ Compilers

Article ID: Q112638

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

Every Windows dynamic-link library (DLL) should include a termination

function called as a Windows Exit Procedure (WEP) to perform general

purpose cleanup operations when Windows unloads a DLL from memory. Under

Windows version 3.0, WEPs are not implemented properly; however, under

Windows version 3.1, the design of WEPs is enhanced to perform cleanup

operations. Also, Microsoft C/C++ versions 7.0 and later provide a default

WEP for DLLs in the standard C run-time libraries. This article discusses

some issues that relate to WEPs in the various Windows environments.

MORE INFORMATION

================

As mentioned earlier, every Windows DLL typically includes a Windows Exit

Procedure (WEP), which should be the last function called in the last

reference to a DLL before the DLL is removed from memory.

WEPs under Windows Version 3.0

------------------------------

WEPs were introduced in Windows version 3.0 to allow each DLL that hooked

interrupts and/or modified I/O ports to clean up when the DLL was unloaded.

However, because the initial implementation is flawed and the limitations

not well documented, the use of WEPs in Windows version 3.0 is very much

limited.

WEPs Under Windows Version 3.1

------------------------------

Here are some general rules in building WEPs:

 - All DLLs must have a WEP. Even if the WEP does not do anything, the WEP

   must still be defined. An exception to this rule is when you are using

   any of the C/C++ compilers from Microsoft. This exception is discussed

   in a later section of this article.

 - A WEP must be declared as a FAR PASCAL function.

 - A WEP must be exported by listing it in the EXPORTS section of the DLL's

   DEF file. The RESIDENTNAME keyword and any ordinal reference must be

   associated with it (so that Windows can find the WEP routine, even when

   there is little available memory, without loading anything from disk).

   For example:

      EXPORTS

        WEP     @1     RESIDENTNAME

   NOTE: It is not necessary to use 1 as the ordinal reference; any number

   can be used.

Changes to WEPs Under Windows Version 3.1

-----------------------------------------

Several changes were made to the implementation of WEPs under Windows

version 3.1. The following comprehensive list of changes compares the

implementation in Windows 3.0 to that in Windows 3.1:

 - In Windows version 3.0, the WEP is called on a very small stack located

   in the Windows Kernel module, which will overflow if the WEP function

   calls Windows APIs and MS-DOS functions. The reason for this is that the

   WEP was originally designed to allow a DLL that hooked an interrupt to

   unhook it before termination, and not as a general purpose cleanup

   routine. The small Kernel stack was enough to unhook an interrupt,

   however.

   In Windows version 3.1, the WEP is called on a 4K stack in Kernel, which

   provides enough room to call Windows APIs and MS-DOS functions, and

   perform any cleanup operation.

 - In Windows version 3.0, if a DLL uses another DLL (which is implicitly

   referenced), the DLL's WEP function can be called after the associated

   DLL is freed. If the segment that contains the WEP is discarded while

   containing references to the associated DLL, the system crashes when the

   WEP's segment is reloaded. This happens when Windows attempts to fix up

   the external references to the already freed DLL. The fix for this

   problem was to keep the WEP routine in a FIXED segment.

   In Windows version 3.1, all affected WEPs are called before any DLLs are

   freed or discarded. Thus, WEPs can reside in discardable segments in

   DLLs written explicitly for Windows version 3.1.

 - For the same reason mentioned above, in Windows version 3.1, a WEP can

   also call functions in other DLLs. The caveat here is that a DLL must

   not rely on library unload order on its own implicitly link DLLs. The

   Windows loader may have unloaded your DLL making the function call

   result in a general protection (GP) fault. The safe functions to call

   are any that reside in the core libraries such as USER, KERNEL, and GDI.

 - In Windows version 3.0, under some low memory situations, the WEP can be

   called before the library initialization routine has been called.

   In Windows version 3.1, Windows calls a WEP only if the library entry

   point function has been called. The WEP code, for DLLs written

   specifically for Windows version 3.1, no longer needs to track this

   itself.

 - In Windows version 3.0, under some low memory situations, the WEP can be

   called before the library's DGROUP has been created.

   Windows version 3.1 ensures that the automatic data segment is allocated

   before the WEP is called. The WEP code can assume that DS is valid and

   that it contains the selector to the DLL's data segment.

 - Under rare circumstances, the WEP for a DLL can be called more than once

   in Windows version 3.0. In Windows version 3.1, the WEP is never called

   more than once.

 - In Windows version 3.0, the USER module is notified that a DLL is freed

   before the WEP is called. Thus, any resources, such as registered

   classes, are freed by the USER module before the WEP is called. In

   Windows 3.1, USER is notified after the WEP is called.

 - Because the Microsoft Windows version 3.0 SDK documentation is unclear

   concerning the return value from a WEP, the WEP code in some existing

   DLLs does not do a RETF 2. Windows version 3.1 saves and restores the

   value of SP around the call to the WEP.

WEPs Under Microsoft C/C++ Versions 7.0 and Later

-------------------------------------------------

As mentioned earlier, beginning with Microsoft C/C++, the standard C run-

time libraries that support DLLs for Windows (xDLLCyW.LIB) contain a

default Windows exit procedure WEP(), a default entry-point procedure

LibEntry() in the LIBENTRY.OBJ file, and a default library initialization

procedure LibMain(). Therefore, if you link to one of the C run-time

libraries provided with Microsoft C/C++ versions 7.0 and later, you no

longer need to provide your own WEP() or LibMain() routine or link to a

LIBENTRY.OBJ file.

The LibEntry() procedure in the DLL C run-time libraries performs all the

necessary initialization required by the WEPs they contain. The LibEntry()

procedure in the default LIBENTRY.OBJ file will call a default LibMain()

procedure. The default LibMain() procedure returns and does nothing useful.

Remember that no initialization will be done if you use the default

LibMain(). However, your DLL could define its own LibMain() function so as

to perform any type of additional initialization processing that it needs

(for example, registering custom control classes or allocate global memory,

and so forth). In such a case, the LibMain() in your DLL will be called

instead of the default LibMain() in the run-time library.

To use the default run-time library's LibEntry() procedure, just do not

link to a LIBENTRY.OBJ file. To use the default run-time library's

LibMain() function, do not provide a LibMain() function in your DLL.

Similarly, the C run-time libraries call a default version of the WEP

function at the time a DLL needs to be unloaded from memory. The source

code for the default WEP routine is included in a file called WEP.ASM in

the SOURCE\STARTUP\WIN directory of Microsoft C/C++ version 7.0 or later.

This default WEP routine just returns and does nothing useful [other than

performing some C exit processing by calling _cexit()].

To use the default run-time library's WEP routine, just include the

following lines in the .DEF file:

   SEGMENTS 'WEP_TEXT' FIXED PRELOAD

   EXPORTS

       WEP @1 RESIDENTNAME

Because the WEP's code is very small, making the WEP_TEXT segment fixed in

memory should not adversely impact Windows's performance.

However, in certain cases there is a need to link into your own WEP routine

instead of the default WEP routine provided by the Microsoft C/C++

compiler. This is possible, because the default WEP calls an optional user

termination function _WEP. Therefore, to add your own processing to the

default WEP function, add a _WEP function as follows:

   int FAR PASCAL _WEP (int ExitCode)

   {

     //

     // Include exit cleanup code here

     //

     return ExitCode;

   }

NOTE: Unlike the default WEP routine, the name of your routine must begin

with a leading underscore. If a _WEP routine is not provided in a DLL, the

default WEP routine will call the default _WEP routine, which simply

returns a 1. In the case where you define your own _WEP routine, LINK.EXE

will resolve references to _WEP to your _WEP instead of the default _WEP

that exists in the DLL C run-time library (as long as you put the object

file that contains your _WEP to the left of the DLL run-time library in the

LINK command line).

NOTE: The default WEP routine provided by the run-time libraries assumes

protected-mode operation only because it calls the LAR instruction in its

source code, which is a protected-mode instruction only, and therefore will

not work in real mode (for example, under Windows 3.0).

NOTE: The default WEP provided by the Microsoft C/C++ run-time libraries

calls a routine in WIN87EM.DLL, which is the Windows 80x87 floating-point

emulation library. Under certain situations, the WIN87EM library might have

been unloaded from memory by the time the default WEP routine is called. If

this causes problems, copying WIN87EM.DLL to WIN87EM.EXE and placing it on

the LOAD= line of WIN.INI will ensure the usage count of WIN87EM will never

reach zero.

NOTE: Avoid making recursive calls or calling MS-DOS functions or using

file I/O in the _WEP routine, if you provide one in the DLL.

NOTE: Because the initialization and termination operations performed by

the LibEntry and WEP functions in the C run-time libraries are correlated,

you should use them both, or neither. If you use your own WEP, then you

should link to LIBENTRY.OBJ; if you use the C run-time library's WEP, you

should use its LibEntry as well.

For more information, refer to the DETAILS.TXT file that is shipped with

Microsoft C/C++ version 7.0 or later.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrDll


Intel Privileged and Sensitive Instructions

Article ID: Q114473

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Intel architecture defines "privileged" instructions and "sensitive"

instructions. The privileged instructions may only be executed when the

Current Privilege Level is zero (CPL = 0). Attempting to execute a

privileged instruction when CPL != 0 will generate a general protection

(GP) exception. Windows traps GP exceptions caused by executing

privileged instructions and usually generates an application error.

The sensitive instructions (also called IOPL-sensitive) may only be

executed when CPL <= IOPL (I/O Privilege Level). Attempting to execute a

sensitive instruction when CPL > IOPL will generate a GP exception. This

should usually not cause a fatal error. The Windows Virtual Machine

Manager (VMM) traps GP exceptions caused by executing sensitive

instructions and (depending on the instruction) either simulates the

instruction's behavior in the VM in which the instruction was executed,

or dispaches it to a virtual device driver, which simulates the

instruction's behavior.

The Virtual Machine Manager (VMM), which is in WIN386 along with the

core Virtual Device Drivers (VxDs), runs at CPL = 0. By Intel hardware

definition, Virtual 8086 (V86) mode always runs at CPL = 3. In enhanced

mode, the machine can be either in IOPL = 0 or IOPL = 3.

MORE INFORMATION

================

The privileged instructions include:

    CLTS - Clear Task-Switched Flag    LMSW    - Load Machine Status

    HLT  - Halt Processor              LTR     - Load Task Register

    LGDT - Load GDT Register           MOV CRn - Move Control Register

    LIDT - Load IDT Register           MOV DRn - Move Debug Register

    LLDT - Load LDT Register           MOV TRn - Move Test Register

The sensitive instructions in protected mode include:

    IN  - Input           OUTS - Output String

    INS - Input String    CLI  - Clear Interrupt-Enable Flag (IF)

    OUT - Output          STI  - Set IF

The instruction POPF is both IOPL and CPL sensitive. IOPL will only be

changed by POPF when executed at CPL = 0. The interrupt flag (IF) will

only be changed by POPF if executed with CPL <= IOPL. If POPF does not

change IOPL or the interrupt flag due to lack of privilege, no exception

is generated.

The sensitive instructions V86 mode include:

    CLI   - Clear IF      POPF  - Pop Flags

    STI   - Set IF        INT n - Software Interrupt

    PUSHF - Push Flags    IRET  - Interrupt Return

The CPL = 3 by definition in V86 mode. If IOPL < 3, attempting to execute

V86 mode sensitive instructions will generate a GP exception. The

Windows VMM will trap the GP exception and emulate the instruction in

the VM in which it was originally executed.

I/O instructions are special in that they are sensitive not only to

IOPL, but also to the IO permission bitmap in the Task State Segment

(TSS). If CPL <= IOPL, then the I/O operation will proceed without

checking the I/O permission bitmap. If CPL > IOPL, or if in V86 mode, then

the I/O permission bitmap is consulted. If the bits corresponding to the

I/O port are clear, the I/O operation proceeds, otherwise, a GP

exception is generated. In response to this GP exception, the VMM gets

control and dispatches control to the VxD that traps the port.

REFERENCE

=========

For additional information, please see the following article(s) in the

Microsoft Knowledge Base:

ARTICLE-ID: Q100947

TITLE     : Port Trapping in Windows 3.0/3.1

ARTICLE-ID: Q112298

TITLE     : DOCERR: Port I/O with inp() and outp() Fails on Windows NT

Also see the Intel "i486(TM) Microprocessor Programmer's Reference Manual"

and the section "The Effect of Priviledge Levels" in the article "The Tao

of Interrupts" on the Microsoft Developer Network (MSDN) Development

Library CD.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMisc


How to Move Data Between Large Overlapping Buffers

Article ID: Q117743

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Programmers often need to move large amounts of data between buffers in

their applications. The Microsoft Windows version 3.1 API and the Microsoft

C Run Time library provide several functions to let you copy and move data

between buffers. However, none of these functions guarantees that data

larger than 64K can be moved safely between buffers that overlap. This

article lists a C function based on the hmemcpy() Windows version 3.1

function to accomplish this job.

MORE INFORMATION

================

For example, the functions hmemcpy() and MemoryWrite() handle buffers

greater than 64K, but do not guarantee that data can be safely moved

between overlapping buffers. The function _fmemmove() guarantees that data

can be safely moved between overlapping buffers, but does not handle more

than 64K.

Below is a C function that provides that functionality. It recognizes and

covers the four cases that arise while moving data. The four cases are:

 - The source and the destination are identical.

   -or-

 - The source and the destination do not overlap.

   -or-

 - The source and the destination overlap and the source starts at a

   location before the destination in the address space.

   -or-

 - The source and the destination overlap and the source starts at a

   location after the destination in the address space.

Cases 1 and 2 are easy to handle, as seen in the sample code below. In

cases 3 and 4, the address space must be divided into smaller units so that

the data can be moved in small chunks, thus better ensuring the integrity

of the data. In the best case, cases 3 and 4 require only two calls to

hmemcpy(). In the worst case, cases 3 and 4 require "len" number of calls

to hmemcpy(), where len is the number of bytes to move.

The interface to SafeCopy() is identical to that of hmemcpy().

   void SafeCopy(void _huge *d, void _huge *s, long len)

   {

        register long i;

        long safesize, times;

        // There are four cases to consider

        // case 1: source and destination are the same

        // case 2: source and destination do not overlap

        // case 3: source starts at a location before destination in

        //         linear memory

        // case 4: source starts at a location after destination in

        //         linear memory

        // detect case 1 and handle it

        if (d == s)

             return;

        // determine the amount of overlap

        if (d > s)     // get the absolute difference

             safesize = ((unsigned long)d - (unsigned long)s);

        else

             safesize = ((unsigned long)s - (unsigned long)d);

        // detect case 2

        if (safesize >= len)

        {

             hmemcpy(d, s, len);  // no overlap

             return;

        }

        times = len/safesize;

        // detect case 3 and handle it

        if ((s < d) && ((unsigned long)s+len-1) >(unsigned long)d)

        {

             // copy bytes from the end of source to the end of

             // destination in safesize quantum.

             for (i = 1; i <= times; i++)

                  hmemcpy((void _huge *)((unsigned long) d+len-i*safesize),

                          (void _huge *)((unsigned long)s+len-i*safesize),

                           safesize);

             // copy the bytes remaining to be copied after

             // times*safesize bytes have been copied.

             if (times*safesize < len)

                  hmemcpy(d, s, len - times*safesize);

        }

        else // this is case 4. handle it

        {

             // ASSERT (s > d) && ((d+len-1) > s))

             // copy bytes from the beginning of source to the

             // beginning of destination in safesize quantum

             for (i = 0; i < times; i++)

                  hmemcpy((void _huge *)((unsigned long)d+i*safesize),

                          (void _huge *)((unsigned long)s+i*safesize),

                          safesize);

             // copy the bytes remaining to be copied after

             // times*safesize bytes have been copied.

             if (times*safesize < len)

                  hmemcpy((void _huge*)((unsigned long)d+times*safesize),

                          (void _huge*)((unsigned long)s+times*safesize),

                          len - times*safesize);

        }

        return;

   }

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: KrMm


Using WM_COMMNOTIFY in an MFC Application

Article ID: Q119206

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Foundation Classes (MFC) version 2.0 for Microsoft Windows

version 3.1 does not encapsulate the WM_COMMNOTIFY message and the Windows

Communications API. Therefore, MFC applications that need to use the

Windows Communications API have to wrap that API into their classes. This

article discusses the steps involved in that process.

MORE INFORMATION

================

The steps to incorporate WM_COMMNOTIFY-based communications support to your

MFC-based Windows-based application are as follows:

1. Specify a handler for the WM_COMMNOTIFY message using the OnMessage

   macro. The code to implement this step is shown below:

      // In the class header file,

      // generated message map functions protected:

      //{{AFX_MSG(CMfccommView)

           afx_msg LRESULT OnCommNotify(WPARAM wParam, LPARAM lParam);

           <other handlers>

      //}}AFX_MSG

      DECLARE_MESSAGE_MAP()

      // In the source file defining the class:

      BEGIN_MESSAGE_MAP(CMfccommView, CView)

           //{{AFX_MSG_MAP(CMfccommView)

           ON_MESSAGE(WM_COMMNOTIFY, OnCommNotify)

           <other mappings>

           //}}AFX_MSG_MAP

      END_MESSAGE_MAP()

2. Write the handler procedure OnCommNotify() to trap the CN_EVENT,

   CN_RECEIVE, and CN_TRANSMIT notifications.

3. Because WM_COMMNOTIFY is a message, it is always sent to a window. If

   you do not already have a window handle to receive this message, use the

   Create() member of the CWnd class to create a hidden window (do not

   specify WS_VISIBLE) and use that handle (m_hWnd member) in the call to

   EnableCommNotification().

   NOTE: Remember that merely creating an instance of CWnd does not create

   a window. A common error is to derive a class from CWnd and to call

   EnableCommNotification() in the constructor of the derived class. This

   fails because the window handle, m_hWnd, is NULL at this point.

4. Because you cannot return values from the constructor, the constructor

   is not a suitable place for initializing the communications port and

   device. Perform all initializations outside of the constructor in a

   member function created for initialization purposes. Remember to check

   all the return values from the communications API.

Additional reference words: 3.10 comm COM open close

KBCategory: kbprg

KBSubcategory: KrCommapi


Transmitting a BREAK Signal

Article ID: Q119506

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

A BREAK signal is a communications signal that allows two communications

devices to transmit a "break" in the transmission line. This article

discusses how a communications program implemented using the Microsoft

Windows Communications API (Comm API) can send a BREAK signal.

MORE INFORMATION

================

Despite its name, a BREAK signal may be employed to convey just about any

special condition as long as the sender and the receiver know the semantics

of the signal. A BREAK signal, sometimes mistakenly referred to as a BREAK

character, is any SPACE condition on the communication line that lasts

longer than a character and its framing bits.

Comm API contains two functions, SetCommBreak() and ClearCommBreak(), to

assist in sending a BREAK signal. Merely calling these two functions in

sequence will not cause a BREAK signal to be sent. Use one of the two

methods described below to transmit the BREAK signal:

Method 1

--------

The International Consultative Committee for Telephone and Telegraph

(CCITT) modem recommendations require a break signal to be at least "2m+3"

bits long, where "m" is the nominal number of bit times in an asynchronous

character, usually 10; this means that the minimum break time is 23 bits,

with no maximum specified. Usually, much more than the minimum is sent,

such as 100 or 200 milliseconds (that is, hundreds of bit times at high

data rates). The timer resolution in a PC is sufficient for sending such

"long" BREAK signals, but not sufficient to send exactly 23 bit times.

An application can call SetCommBreak() to initiate the BREAK signal. Use

SetTimer() to set a timer and wait for the recommended duration, and then

call ClearCommBreak() to terminate the BREAK signal.

NOTE: If an application sends some data and subsequently calls

SetCommBreak() before that data has had a chance to make its way through

the transmit first in, first out algorithm (FIFO), the data will actually

be overwritten by the SetCommBreak() and not get onto the line. To prevent

such corruption, it is recommended that you pause for a while before the

SetCommBreak().

Method 2

--------

An alternative means of sending a BREAK signal of shorter duration is to

temporarily change the data rate in the UART to half or 1/4 of the actual

line speed and then send a single NULL byte. This is more precise than

using SetCommBreak() and ClearCommBreak(), but it has the disadvantage of

corrupting received data during the time the BREAK signal is being sent

(because the received data rate is wrong during that time). An application

can change the date rate in the UART with a call to SetCommState(). The DCB

structure passed to SetCommState() specifies the new data rate.

REFERENCES

==========

For more information on the BREAK signal and the SPACE character, please

refer to "C Programmer's Guide to Serial Communications," second edition,

by Joe Campbell, published by SAMS Publishing.

Additional reference words: 3.10 COM interrupt

KBCategory: kbprg

KBSubCategory: KrCommapi


PC Hangs While Running a Communications Application

Article ID: Q119853

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article provides information about a problem that has appeared on

recently manufactured IBM PCs and PC compatibles. Many of these machines

incorporate the Peripheral Component Interface (PCI) bus, giving the

impression that the problem may be somehow related to this bus. The

problem, however, can occur on machines with other bus architectures. An

obvious symptom of this problem is that when a comm port is opened and

closed a couple of times, the machine hangs, forcing the user to reboot

the PC.

MORE INFORMATION

================

There is a problem with a Super I/O chip (SMC '665) that many OEMs used to

provide serial ports on their latest generation (typically PCI-bus-based)

PCs. This problem can (and has) shown up on PCs that do not have a PCI bus.

Having the bad chip is all that is needed to cause this problem.

The problem is that if you reset the first in, first out algorithm (FIFO)

by clearing and then enabling it when the port is initializing, and there

is already a character in the receive FIFO, the comm driver gets an

indication that a new character has been received. The driver, of course,

tries to get this character. Unfortunately, the driver keeps finding that a

new character is available even if no more characters have been received.

In this case, you can do nothing short of a cold reboot to get rid of this

indication. Any workaround should, therefore, avoid this situation

altogether.

A workaround involving a driver is to disable the FIFO, read a character,

then reenable it. A workaround if you do not have access to a driver is to

disable the FIFO feature of the 16550 UART. You can accomplish this by

editing (adding the entry if it does not exist) the COMxFIFO key (x = 1, 2,

etc. for COM1, COM2, etc.) of the [386Enh] section in the SYSTEM.INI file.

For example, the FIFO for COM2 can be disabled with the following entry:

   [386Enh]

   COMXFIFO=0

NOTE: Disabling a comm port's FIFO reduces its data throughput.

The COMM.DRV communications driver shipped with Windows version 3.x and

SERIAL.386 shipped with Microsoft Windows For Workgroups version 3.11 do

not offer a workaround for this problem. Users of Windows for Workgroups

version 3.11, however, can download an upgrade to SERIAL.386; this upgrade

works around the problem. Users of Windows version 3.x have to obtain a

third-party communications driver that implements a workaround (or

explicitly disables the FIFO) to solve the problem.

REFERENCES

==========

The updated SERIAL.386 file for Windows for Workgroups version 3.11 is

included with PSS Application Note WG1001, "Updated SERIAL.386 Driver for

Windows for Workgroups" (also found in KB article Q112300).

For more information about WG1001, query on the following word in the

Microsoft Knowledge Base:

   WG1001

Additional reference words: 3.00 3.10 WfW 3.11 COM freeze OpenComm

CloseComm hung frozen

KBCategory: kbprg

KBSubCategory: KrCommapi


Determining System Version from a Windows-Based Application

Article ID: Q131371

-----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

-----------------------------------------------------------------------

SUMMARY

=======

To create a Windows-based application that takes advantage of the features

of each platform, it is necessary to determine what operating system the

application is currently running with.

The GetVersion() function can be used to determine what operating system

and version is currently being used. A 16-bit Windows-based application

might be running with Microsoft MS-DOS/Microsoft Windows, Microsoft

Windows NT Workstation, Microsoft Windows NT Server, or Microsoft Windows

95. Windows on Win32 (WOW) is the term given for the operating environment

when running a 16-bit Windows-based application with Microsoft Windows NT

Workstation or Microsoft Windows NT Server.

MORE INFORMATION

================

According to the documentation, the return value of the GetVersion()

function is a DWORD that specifies the major and minor version numbers.

The following table shows the return values from the GetVersion() function

when used with various operating environments:

   Environment   LOWORD                 HIWORD

   -------------------------------------------------------

   Windows 3.x   Windows version        MS-DOS version

   WFW           Windows version 3.1    MS-DOS version

   WOW           Windows version 3.1    MS-DOS version 5.0

   Windows 95    Windows version 3.95   MS-DOS version 7.0

Microsoft Windows operating system version 3.1 and WOW can return the same

results. Therefore, 16-bit Windows-based applications may want to use the

GetWinFlags() function to determine whether the application is being run

with Microsoft Windows or WOW. The GetWinFlags() function returns a

WF_WINNT flag if the application is running with WOW.

GetWinFlags() is an existing function that has been modified to detect

other platforms. To test for Microsoft Windows NT, add the following

flag to your header file and use it to perform the test:

   #define WF_WINNT         0x4000

The following sample code can be used to test the values returned by the

GetVersion() function.

Sample Code

-----------

#include <windows.h>

void main()

{

   DWORD dwVersion;

   char szVersion[80];

   dwVersion = GetVersion();

   wsprintf (szVersion, "Microsoft Windows %u.%u - MS-DOS %u.%u",

            (DWORD)(LOBYTE(LOWORD(dwVersion))),

            (DWORD)(HIBYTE(LOWORD(dwVersion))),

            (DWORD)(HIBYTE(HIWORD(dwVersion))),

            (DWORD)(LOBYTE(HIWORD(dwVersion))));

   MessageBox( NULL, szVersion, "Version Check", MB_OK );

}

If you want to be able to distinguish between Windows and Windows for

Workgroups, use the following test.

Sample Code

-----------

   #define WNNC_NET_MultiNet           0x8000

   #define WNNC_SUBNET_WinWorkgroups   0x0004

   #define WNNC_NET_TYPE               0x0002

   HINSTANCE hModInst      = NULL;

   FARPROC   lpWNetGetCaps = NULL;

   WORD      wNetType;

   hModInst = LoadLibrary( "USER.EXE" );

   if( !(lpWNetGetCaps = GetProcAddress( hModInst, (LPSTR)"WNetGetCaps")) )

      MessageBox (hWnd, "WNetGetCaps Not Found", NULL, MB_OK);

   else

   {

   // Get the network type

      wNetType = (*lpWNetGetCaps) (WNNC_NET_TYPE);

      if( wNetType & WNNC_NET_MultiNet )

      {

      // a multinet driver is installed

         if( LOBYTE(wNetType) & WNNC_SUBNET_WinWorkgroups )

         // It is WFW

            MessageBox( hWnd, "Windows for Workgroups", NULL, MB_OK);

         else

         // It is not WFW

            MessageBox( hWnd, "Not Windows for Workgroups", NULL, MB_OK);

      }

   }

   // Clean up the module instance

   if( hModInst )

      FreeLibrary( hModInst );

Additional reference words: 3.10 detect

KBCategory: kbprg

KBSubcategory: KrMisc


How to Access Physical Memory in 16-bit Windows-Based Apps

Article ID: Q131426

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0, 3.1, and 4.0

---------------------------------------------------------------------

SUMMARY

=======

Some Windows-based applications need direct access to a range of physical

addresses so that they can interact with memory-mapped hardware interface

cards or read the computer's CMOS settings. This article outlines two

methods 16-bit Windows-based applications can use to access a region of

physical memory directly. Neither method, however, provides memory

allocation and management; applications must use the standard memory

management functions for allocating and managing memory.

MORE INFORMATION

================

Method One: Exported Selectors (Preferred)

------------------------------------------

The 16-bit Windows kernel (KRNL386.EXE) exports several selectors that

should be used by 16-bit applications that need to read or write to

physical memory addresses below 1 megabyte (MB). The exported selectors

are:

   __0000h, __0040h, __A000h, __B000h, __B800h, __C000h, __D000h,

   __E000h, and __F000h

To use one of these selectors, place it onto a segment register and access

the memory or create a far pointer. Here are examples using the Microsoft

Macro Assembler (MASM) and Microsoft C:

  In MASM:    extern  __0040h

              ...

              mov ax, __0040h

              mov es, ax

     In C:    extern   WORD _0040h;

              LPSTR    lpBIOSDataArea;

              ...

              /* Note the ampersand (&) and underscore (_) below */

              lpBIOSDataArea = (LPSTR)MAKELONG(0, &_0040h);

   In C++:    extern "C" WORD _0040h;

              LPSTR    lpBIOSDataArea;

              ...

              /* Note the ampersand (&) and underscore (_) below */

              lpBIOSDataArea = (LPSTR)MAKELONG(0, &_0040h);

Each of these selectors is limited to addressing 64K. Attempts to read or

write data beyond the 64K limit cause a general protection (GP) fault.

Applications must not free these selectors.

Applications should use exported selectors unless they do not provide

access to the necessary area of physical memory. In which case, you can try

method two.

Method Two: Selector Synthesis

------------------------------

When an application needs to access physical memory that is not addressable

with the selectors exported from the Windows kernel, it can allocate a new

selector and initialize the associated descriptor with the appropriate base

address and limit. The Windows kernel and the DOS Protected Mode Interface

(DPMI) server (part of Windows) provide functions for applications to do

this. Each required function is described below:

Map Physical To Linear

   (DPMI: Interrupt 31h, AX=0800h) Obtains a 32-bit linear address that

   corresponds to a specified 32-bit physical address. This function is

   needed because the selector functions require linear addresses. In

   Windows version 3.1 standard mode, this function is not required because

   linear addresses are the same as physical addresses.

AllocSelector(WORD wSelector)

   (Kernel) Allocates a new selector or array of tiled selectors and copies

   the attributes of wSelector to the new selectors. If the limit of

   wSelector is less than or equal to 64K, a single selector is allocated.

   If the limit of wSelector is larger than 64K, an array of tiled

   selectors is allocated such that each selector points to one 64K portion

   of the limit of wSelector.

FreeSelector(WORD wSelector)

   (Kernel) Frees either a single selector or an array of tiled selectors

   depending on the limit of wSelector. Frees one selector for each 64K

   portion of the limit of wSelector. The selector or array of tiled

   selectors being freed must have been allocated previously by

   AllocSelector. Furthermore, the limit of wSelector must be identical

   to that used by the selector as a parameter in the call to

   AllocSelector.

SetSelectorBase(WORD wSelector, DWORD dwBase)

   (Kernel) Stores the starting linear address of the desired region in the

   descriptor of wSelector.

SetSelectorLimit(WORD wSelector, DWORD dwLimit)

   (Kernel) Stores the length of the desired region in the descriptor of

   wSelector.

PrestoChangoSelector (WORD wSourceSelector, WORD wDestSelector)

   (Kernel) Copies the attributes of wSourceSelector into wDestSelector and

   toggles the code/data attribute. That is, if wSourceSelector is a code

   selector, the wDesSelector will be a copy of it, except wDestSelector

   has the data attribute instead of the code attribute. wDestSelector must

   have been allocated previously by AllocSelector.

Four Caveats to Keep in Mind

----------------------------

1. Allocating selectors does not actually allocate any memory. It merely

   creates a pointer that can be used to access existing memory (memory

   previously allocated or provided by a memory-mapped hardware device). Do

   not confuse allocating selectors with allocating memory.

2. Selectors that alias (point to) a memory block allocated by Windows are

   not updated if the memory block is moved. To ensure that the memory

   block is not be moved, call GlobalFix() on it before creating a selector

   that aliases it. However, if the synthesized selector points to memory

   provided by a physical device, there is no need to call GlobalFix()

   because the device's memory was not allocated by Windows.

3. The Windows memory manager does not keep track of which task allocated

   selectors with these functions, so you must ensure that the task frees

   them correctly. In particular, make sure it does not free more or less

   selectors than it allocates. The sample code below demonstrates the

   proper way to allocate and free selectors with these functions.

4. Allocating large numbers of selectors is discouraged because selectors

   are a limited resource.

The following code was written using the inline assembly feature of the

Microsoft C and C++ compilers. This code illustrates how to create a huge

pointer to a range of physical addresses.

Sample Code

-----------

DWORD MapPhysicalToLinear(DWORD, DWORD);

void __huge * CreateHugePointer (DWORD dwLinearBase,

                                 DWORD dwLength);

void FreeHugePointer (void __huge * hPtr);

DWORD dwPhysical, dwLinear, dwLength;

char __huge *hpPhysMem;  // Will point to physical addresses

WORD  segment, offset;   // These variables are necessary only

                         // if the target memory is addressed

                         // with a "real-mode" style SEG:OFFSET

                         // pointer.

/*--------------------------------------------------------------*/

/*     Sample Code to Create a Pointer to Physical Memory       */

/*--------------------------------------------------------------*/

/*

  Create a linear address. The way to do this depends on

  where the memory is located. Both ways are shown below,

  but only *one* must be used.

*/

   /*

     Obtain linear address below 1 MB

     If the selector will point to memory below 1 MB, create a

     linear address as follows (yes, this really is a linear

     address):

   */

dwLinear = ((DWORD)segment << 4L) + offset;

   /*

     Obtain linear address above 1 MB

     If the selector will point to memory above 1 MB, dwPhysical

     should contain the 32-bit physical address. Call DPMI to

     convert dwPhysical to a linear address. Note that you must

     pass the physical address and the length (limit) to DPMI.

   */

dwPhysical = 0xC000000;    // Physical 192 MB address

                           // (for example purposes only).

dwLinear = MapPhysicalToLinear(dwPhysical, dwLength);

if (!dwLinear)

   {

   ;// Handle error...

   }

   /*

     Now that dwLinear contains the linear address, it's time to

     create a pointer so you can access the physical memory.

   */

hpPhysMem = CreateHugePointer (dwLinear, dwLength);

// Use the pointer hpPhysMem to access memory...

   // Free the pointer when finished with it

FreeHugePointer(hpPhysMem);

// Rest of program...

/*--------------------------------------------------------------*/

/* Functions used to create huge pointers to physical memory    */

/*--------------------------------------------------------------*/

/*----------------------------------------------------------------

   This function is a wrapper for DPMI Map Physical To Linear.

   Returns 0 if it failed or if the physical address is below

   1 MB. Returns the linear address if DPMI call succeeded.

----------------------------------------------------------------*/

DWORD MapPhysicalToLinear(DWORD dwPhysical, DWORD dwLength)

   {

   DWORD dwLinear = 0L;          // In case memory below 1 MB, you

                                 // don't want to return garbage.

   if (dwPhysical >= 0x100000L)  // Use only if above 1 MB.

      {

      _asm {

           push    di

           push    si

           mov     bx, WORD PTR [dwPhysical+2] ; Load arguments.

           mov     cx, WORD PTR [dwPhysical]

           mov     si, WORD PTR [dwLength+2]

           mov     di, WORD PTR [dwLength]

           mov     ax, 800h

           int     31h                         ; Issue DPMI call.

           jnc     short fine_return

           xor     bx, bx                      ; zero out return

           mov     cx, bx                      ; regs on error

   fine_return:

           mov     WORD PTR [dwLinear+2], bx   ; Return value.

           mov     WORD PTR [dwLinear], cx

           pop     si

           pop     di

           }

      }

   return dwLinear;

   }

/*--------------------------------------------------------------

   This function creates a huge pointer with the proper number

   of selectors to access up to 1 MB of physical memory. The

   huge pointer may be used by normal C or C++ code. Returns

   the huge pointer if it succeeded or NULL if it failed.

--------------------------------------------------------------*/

void __huge * CreateHugePointer (DWORD dwLinearBase,

                                 DWORD dwLength)

   {

   WORD tempSelector = NULL;

   WORD codeSelector = NULL;

   WORD dataSelector = NULL;

   /*

     SetSelectorLimit does not handle the granularity bit of

     selectors properly, so this function is limited to creating

     selectors whose limits are less than 1 MB.

   */

   if (dwLength > 0xFFFFF)

      return NULL;

   /*

     Allocate *one* temporary selector by making a copy of the

     code segment selector and converting the copy to a data

     selector. Code segments are always less than or equal to

     64 K, so you are guaranteed to get a single temporary selector,

     so you can be sure to free a single selector.

     Once you have the temporary selector, set its base address and

     limit to the desired values, which may be larger than 64 K.

     Because the memory must be accessed by 16-bit code, you must

     allocate an array of tiled selectors. The temporary selector is

     used to force AllocSelector() to allocate an array of the proper

     number of tiled selectors each with the proper base and limit.

     Then, you can free the single temporary selector.

     If you fail anywhere along the way, clean up whatever has been

     done, and return NULL.

   */

   _asm {

        mov ax, cs

        mov codeSelector, ax

        }

   tempSelector = AllocSelector (codeSelector);

   if (!tempSelector)

      return NULL;

   /*

     If we can successfully change the tempSelector into a

     data selector, set its base address and limit to the

     desired base and limit, and then allocate the real selector

     array.  Otherwise, just prepare to return NULL;

   */

   if (PrestoChangoSelector (codeSelector, tempSelector))

      {

      SetSelectorBase(tempSelector, dwLinearBase);

      SetSelectorLimit(tempSelector, dwLength);

      dataSelector = AllocSelector(tempSelector);

      }

   else

      dataSelector = NULL;

   // Clean up temp selector

   SetSelectorLimit(tempSelector, 0L);

   FreeSelector(tempSelector);

   // dataSelector will be NULL if it could not be allocated

   // successfully, making this function return NULL.

   return (void __huge *)MAKELONG(0, dataSelector);

   }

/*--------------------------------------------------------------

  This function frees pointers allocated by CreateHugePointer.

  It correctly frees all tiled selectors created to access the

  block of physical memory. It is very important that you call

  this on all pointers created by CreateHugePointer and that you

  do not call this function on pointers allocated by any way

  other than using CreateHugePointer.

--------------------------------------------------------------*/

void FreeHugePointer (void __huge * hPtr)

   {

   if (hPtr)

      FreeSelector (HIWORD(hPtr));

   }

Additional reference words: 3.00 3.10 4.00 Windows 95 Win95

KBCategory: kbprg kbcode

KBSubcategory: KrMm


Using NetBIOS Interrupts Under Windows

Article ID: Q23033

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Windows SDK API NetBIOSCall() is provided as an interface for

application developers using network communication protocols.

MORE INFORMATION

================

The NetBIOSCall() translates to an interrupt 5Ch call and is handled by the

Virtual NetBIOS driver under 386 enhanced mode Windows or by the MS-DOS

Extender (DOSX.EXE) under standard mode.

The interface provides for both synchronous and asynchronous NetBIOS

commands.

When asynchronous commands are used, there are two rules that an

application developer must follow:

 - The POST routine provided to the network control block (NCB)

   MUST be in a fixed code segment in a DLL (dynamic-link library).

   This is necessary because the asynchronous event could complete while a

   BIOS operation is in progress. Because the BIOS is used to reload

   segments, if the event occurred while in the BIOS, it would not be

   possible to reload a not-present segment. A FIXED code segment in a DLL

   remains fixed and page-locked in memory at all times.

 - The NCB and associated read or write buffer for asynchronous commands

   must be allocated as GMEM_FIXED from within a DLL. This ensures that the

   buffers will be page-locked.

It is recommended that synchronous commands not be used if a comparable

asynchronous command is available. Synchronous NetBIOS() commands cause the

entire Windows system to halt until the command completes.

Additional reference words: 3.00 3.10

KBCategory: kbnetwork kbprg

KBSubcategory: NtwkNetBios


Developing Network Applications for Windows

Article ID: Q65125

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article can be found in the Software/Data Library by searching on the

keyword NETWORK, the Q number of this article, or S12690. NETWORK was

archived using the PKware file-compression utility.

NOTE: This article is part of a set of seven articles, collectively called

the "Windows 3.10 Developer's Notes." For more information about the

contents of the other articles, and procedures for ordering a hard-copy

set, please see the following article(s) in the Microsoft Knowledge Base:

ARTICLE-ID: Q65260

TITLE     : The Windows 3.10 Developer's Notes

MORE INFORMATION

================

As local area networks (LANs) become increasingly common, application

developers should ensure that their applications run properly in a network

environment.

There are two areas that developers should keep in mind:

 - Applications should be well behaved when shared by multiple users.

 - Applications that access network software directly might require special

   measures to be compatible with protected (standard or 386 enhanced)

   mode.

This document discusses each of these areas.

There are other forms of networking available to developer which provide a

layer of transparency from the protected vs real mode issues of Windows

network programming. These network interfaces are not discussed in this

article, but may be found in other articles throughout the Microsoft

Knowledge Base. They are: Remote Procedure Calls (RPC), Windows Sockets,

named pipes, mailslots, and NetDDE.

=======================================================================

                   BEING SHARED BY MULTIPLE USERS

=======================================================================

Many corporations are choosing to have their computer users share a single

copy of an application that resides on a network server. Microsoft Windows

version 3.1 can be run this way. The Windows Setup /n (network) option

configures the user's system, which ensures that most Windows files are

used directly off the network, while the user's personal files and

configuration information are stored in a private Windows directory. (See

the "Microsoft Windows User's Guide" for more information on using a shared

copy of Windows.)

If the developer intends to allow shared copies of an application, then the

developer must make sure that two users running the same application will

not interfere with each other. The following sections present rules that

should help the developer design the application for network support.

CREATING PERMANENT FILES

========================

Many applications store configuration files in the same directory as the

application's own executable file. This method will not work for multiple

users because the application will store each user's information in the

same directory, overwriting other users' information.

Instead, the application should use the GetWindowsDirectory() function to

find the user's private Windows directory. This location is guaranteed to

be unique for each user.

Refer to the "Microsoft Windows Software Development Kit Reference"

for more information on the GetWindowsDirectory() function.

CREATING TEMPORARY FILES

========================

When creating temporary files, use the GetTempFilename() function to

determine the name and location of the file. This function will ensure that

temporary filenames will not conflict, even if multiple users are sharing

the same temporary storage directory.

USING PROFILE STRINGS

=====================

Profile and configuration information is usually stored in initialization

(.INI) files using Windows functions such as WriteProfileString(). These

functions fall into two categories: those that access WIN.INI, and those

that access another .INI file specified by the program.

The following functions access WIN.INI:

 - GetProfileString()

 - GetProfileInt()

 - WriteProfileString()

Because each user has a unique copy of WIN.INI, these functions can be used

safely, even when the application is being shared by more than one user.

The following functions access other initialization files:

 - GetPrivateProfileString()

 - GetPrivateProfileInt()

 - WritePrivateProfileString()

These functions behave similarly to the WIN.INI functions, except that the

application specifies the name of the private initialization file. When

using these functions, the developer should specify the name of the file;

however, a complete pathname should not be used (for example, MYAPP.INI

should be used instead of C:\MYAPP\MYAPP.INI.) By default, the file will be

located in the user's private Windows directory; specifying a full pathname

could give multiple users access to the same file.

Initialization files that need to be shared among all users are the

exception to this rule. Make sure that such files cannot be left in an

inconsistent state if multiple users update them simultaneously.

For a full description of the initialization file functions, see the

Windows SDK (Software Development Kit) reference manual.

=======================================================================

             CALLING NETWORK SOFTWARE IN PROTECTED MODE

=======================================================================

Windows-based applications running in protected mode require special

support whenever they make a function call to real-mode software. This

includes calls to MS-DOS, the BIOS, or a network. However, applications

that are not based on Windows but are running with Windows do not require

this special support because they always run in real or virtual-8086 mode.

The main support required is called "API mapping." If the arguments to the

call include pointers to data, that data should be copied down into the

first 1 MB of address space to ensure that the real-mode software can

access it. The processor is then switched into real or virtual-8086 mode to

ensure that the real-mode software can process the call. Finally, when that

call returns, any data it modified is copied back up to the caller's

protected-mode address.

Fortunately, most applications interact with the network only indirectly,

by using MS-DOS functions to manipulate files on redirected drive letters,

or by using MS-DOS or BIOS calls to print to a remote printer using

redirected printer ports. Windows-based applications can continue to

perform these functions normally because Windows automatically maps

standard MS-DOS and BIOS calls.

However, some applications need to use functions that are specific to a

particular network or networking protocol. Some part of the software must

map these APIs, and in some cases this may require special procedures on

the part of the programmer.

The remainder of this document describes programming considerations for

designing Windows-based applications that use the following networking

protocols and networks:

 - Microsoft Networks and MS-DOS network functions

 - NetBIOS functions

 - Microsoft LAN Manager-based networks

 - Novell NetWare

 - Ungermann-Bass Net/One

 - Banyan VINES

MICROSOFT NETWORKS AND MS-DOS NETWORK FUNCTIONS

===============================================

Many networks on the market today are based on the Microsoft Network

standard, also known as MS-NET. These networks support a set of standard MS-

DOS functions that perform network activities, such as redirecting drive

letters.

Windows automatically handles these MS-DOS functions. However, to maintain

compatibility with future Windows products, the application should not make

MS-DOS calls by executing an INT 21H instruction. Instead, it should set up

all the registers for executing the INT 21H and then make a far call to the

Windows DOS3Call() function.

See the Windows SDK reference manual for a full description of the

DOS3Call() function. See the "MS-DOS Encyclopedia," available from

Microsoft Press, for more information on Microsoft Network functions.

NETBIOS FUNCTIONS

=================

NetBIOS is the most widely used networking API. These functions are

normally called using INT 5CH. Windows handles most NetBIOS functions.

However, to maintain compatibility with future Windows products, the

application should not make the NetBIOS call by executing an INT 5CH

instruction. Instead, it should set up all the registers for executing the

INT 5CH, and then make a far call to the Windows NetBIOSCall() function.

The following rarely-used NetBIOS functions are not supported:

   Function  Description

   --------  -----------

   71H       Send.No.Ack

   72H       Chain.Send.No.Ack

   73H       Lan.Status.Alert

   78H       Find.Name

   79H       Trace

See the Windows SDK reference manual for a full description of the

NetBIOSCall() function. See the "IBM Local Area Network Technical

Reference" for more information on NetBIOS.

LAN MANAGER-BASED NETWORKS

==========================

Networks based on Microsoft LAN Manager can be installed in either Basic or

Enhanced versions.

All versions of LAN Manager support MS-NET and NetBIOS functions. However,

if LAN Manager Enhanced is being used with the API option, applications can

also use a powerful set of networking functions.

Applications that are not based on Windows can call these functions by

linking with DOSNET.LIB, a static library provided with the network

software. However, Windows-based applications must use DLLs (Dynamic-Link

Libraries) called NETAPI.DLL and PMSPL.DLL, which are distributed on every

LAN Manager version 2.x Enhanced workstation. Note that these DLLs will not

run on LAN Manager version 1.x or 2.x Basic; therefore, these functions may

only be used on LAN Manager version 2.x Enhanced.

See the "Microsoft LAN Manager Programmer's Reference" for more details on

writing Windows-based applications for LAN Manager.

NOVELL NETWARE

==============

Novell NetWare supports MS-NET and, optionally, NetBIOS functions, which

are described earlier in this document.

In addition, Novell NetWare also supports the NetWare and IPX/SPX API sets,

all based on INT 21H.

Windows-based applications can make NetWare calls; however, this cannot be

done by executing the INT 21H directly because this method is not supported

in all Windows operating modes. Instead, the INT 21H instruction should be

replaced with a far call to the NetWareRequest() function. This function is

exported by name from the NetWare DLL, and should be imported to the module-

definition (.DEF) file as NetWare.NetWareRequest.

UNGERMANN-BASS NET/ONE

======================

Ungermann-Bass Net/One is based upon the Microsoft Network standard. It

supports standard MS-NET and most NetBIOS functions, which are described

earlier in this document.

Net/One also supports private extensions to the NetBIOS function set

(functions 72H-7DH). These functions are supported by the standard

Windows product. These functions can be called as standard NetBIOS

functions would be called, by making a far call to the NetBIOSCall

function.

BANYAN VINES

============

Banyan VINES supports the standard MS-NET and, optionally, NetBIOS

functions. There is also a toolkit for applications that write directly to

the VINES API.

Windows-based applications can call the MS-NET and NetBIOS functions as

previously described.

Additional reference words: 3.00 3.10 Windows 3 Developer's Notes softlib

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkMisc


The Windows 3.10 Developer's Notes

Article ID: Q65260

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Microsoft provides additional information on Windows-based application

development through the "Windows 3.1 Developer's Notes." This information

supplements the documentation that accompanies the Windows 3.1 Software

Development Kit (SDK).

MORE INFORMATION

================

The "Windows 3.1 Developer's Notes" cover a wide range of topics that

are of interest to a relatively small number of Windows developers.

Listed below are the topics currently covered in the developer's

notes.

Because of their size, each note has been placed into a separate

archive file and added to the Software/Data Library. This reduces by

approximately half the amount of connect time necessary to download

any given note. It also provides the option of selecting just one

note or certain notes that apply to a particular situation.

To order a printed copy of all of the developer's notes, in the United

States, please call the Microsoft Information Center at (800) 426-9400

and request "The Windows 3.1 Developer's Notes." The price is

currently $20 plus applicable tax, and shipping and handling charges.

Developers outside the U.S. should contact the Microsoft subsidiary

that serves their country.

The "Windows 3.1 Developer's Notes" contain the following documents:

Filename   S Number   Description

--------   --------   -----------

NETWORK    S12690    "Developing Network Applications for Windows

                     3.00" suggests how to ensure that your

                     application will run properly in a network

                     environment.

EXEFMT     S12688    "Executable-File Header Format" specifies the

                     format of the header of a Windows executable

                     file.

FONTFMT    S12687    "Font-File Format" shows the format of Windows

                     font (.FNT) files.

APLETFMT   S12685    "Windows Accessories Binary File Formats"

                     describes the Windows Write and Windows Calendar

                     file formats.

WINDOS     S12684    "Windows INT 21H and NetBIOS Support for DPMI"

                     describes the support Windows provides for the

                     MS-DOS protected-mode interface specification.

INTLAPPS   S12683    "Writing International Applications for Windows

                     3.00" explains how to create an application that

                     can be adapted readily to non-U.S. markets.

These developer's notes can be found in the Software/Data Library by

searching on the filenames listed above, the Q number of this article,

or the S numbers listed above. These files were archived using the

PKWARE file-compression utility.

Please feel free to submit suggestions for additional developer's

notes topics to Microsoft.

The Software/Data Library contains a Windows-based application setup

utility called WINSET2. For more information on the facilities that WINSET2

provides, query on the following word: WINSET2.

Additional reference words: 3.00 3.10 softlib

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkMisc


Windows APPC for 16 and 32-Bit Windows

Article ID: Q93230

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows APPC Overview

---------------------

Windows APPC defines a standard and consistent API for the 16 and 32-bit

versions of the Microsoft Windows graphical environment. It encompasses a

set of Windows-specific extensions designed to allow the programmer to take

advantage of the message-driven nature of the Windows graphical

environment.

This API has been designed and specified to provide a standard to which

application developers can program and network software vendors can

conform. These API details constitute documentation for application

software developers and a specification for network software vendors.

Network software that conforms to this Windows APPC specification will be

considered "Windows APPC compliant." To be Windows APPC compliant, a vendor

must implement 100 percent of this Windows APPC specification. Suppliers of

such interfaces shall be referred to as "Windows APPC suppliers."

Applications that are capable of exploiting any Windows APPC implementation

will be considered as having a "Windows APPC interface" and will be

referred to as "Windows APPC applications."

The purpose of this document is to specify the Windows APPC interface. It

is assumed that the reader has a basic understanding APPC concepts.

While this is one of the WinSNA APIs to be standardized for the Windows

environment, it is beyond the scope of this document to deal with other SNA

(Systems Network Architecture) APIs.

Microsoft Windows Graphical Environment and Windows-Specific

Extensions

-------------------------------------------------------------

This API has been designed for ALL implementations and versions of the

Windows environment from and including version 3.0. It thus provides for

Windows APPC implementations and Windows APPC applications in both 16- and

32-bit operating environments.

Windows APPC makes provisions for multithreaded Windows-based processes. A

process contains one or more threads of execution. In the Win16 non-

multithreaded world, a task corresponds to a process with a single thread.

All references to threads in this document refer to actual "threads" in

multithreaded Windows environments. In non-multithreaded environments (such

as version 3.0), use of the term thread refers to a Windows process.

The extensions to the Windows environment included in Windows APPC are

provided for maximum programming compatibility between Windows 3.x and

Windows NT and optimum application performance in both environments.

WINAPPC can be found in the Software/Data Library by searching on the word

WINAPPC, the Q number of this article, or S13710. WINAPPC was archived

using the PKware file-compression utility.

Additional reference words: 3.10 softlib WINAPPC.ZIP SNASpec

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkMisc


Windows CPI-C API for 16 and 32-Bit Windows

Article ID: Q93249

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows CPI-C Overview

----------------------

Windows CPI-C defines a standard and consistent API for the 16 and 32-bit

versions of the Microsoft Windows graphical environment. It encompasses a

set of Windows-specific extensions designed to allow the programmer to take

advantage of the message-driven nature of the Windows graphical

environment.

This API has been designed and specified to provide a standard to which

application developers can program and network software vendors can

conform. These API details constitute documentation for application

software developers and a specification for network software vendors.

Network software that conforms to this Windows CPI-C specification will be

considered "Windows CPI-C compliant." To be Windows CPI-C compliant, a

vendor must implement 100 percent of this Windows CPI-C specification.

Suppliers of such interfaces shall be referred to as "Windows CPI-C

suppliers."

Applications that are capable of exploiting any Windows CPI-C

implementation will be considered as having a "Windows CPI-C interface" and

will be referred to as "Windows CPI-C applications."

While this is one of the WinSNA APIs to be standardized for the Windows

environment, it is beyond the scope of this document to deal with other SNA

(Systems Network Architecture) APIs.

Microsoft Windows Graphical Environment and Windows-Specific

Extensions

------------------------------------------------------------

This API has been designed for ALL implementations and versions of the

Windows environment from and including version 3.0. It thus provides for

Windows CPI-C implementations and Windows CPI-C applications in both 16

and 32-bit operating environments.

Windows CPI-C makes provisions for multithreaded Windows-based processes. A

process contains one or more threads of execution. In the Win16 non-

multithreaded world, a task corresponds to a process with a single thread.

All references to threads in this document refer to actual "threads" in

multithreaded Windows environments. In non-multithreaded environments (such

as version 3.0), use of the term thread refers to a Windows process.

The extensions to the Windows environment included in Windows CPI-C are

provided for maximum programming compatibility between Windows 3.x and

Windows NT and optimum application performance in both environments.

WINCPIC can be found in the Software/Data Library by searching on the word

WINCPIC, the Q number of this article, or S13712. WINCPIC was archived

using the PKware file-compression utility.

Additional reference words: 3.10 softlib WINCPIC.ZIP

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkMisc


Windows CSV API for 16 and 32-Bit Windows

Article ID: Q93250

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows CSV Overview

--------------------

Windows CSV defines a standard and consistent API for the 16 and 32-bit

versions of the Microsoft Windows graphical environment. It encompasses a

set of Windows-specific extensions designed to allow the programmer to take

advantage of the message-driven nature of the Windows graphical

environment.

This API has been designed and specified to provide a standard to which

application developers can program and network software vendors can

conform. These API details constitute documentation for application

software developers and a specification for network software vendors.

Network software that conforms to this Windows CSV specification will be

considered "Windows CSV compliant." To be Windows CSV compliant, a vendor

must implement 100 percent of this Windows CSV specification. Suppliers of

such interfaces shall be referred to as "Windows CSV suppliers."

Applications that are capable of exploiting any Windows CSV implementation

will be considered as having a "Windows CSV interface" and will be referred

to as "Windows CSV applications."

While this is one of the WinSNA APIs to be standardized for the Windows

environment, it is beyond the scope of this document to deal with other SNA

(Systems Network Architecture) APIs.

Microsoft Windows Graphical Environment and Windows-Specific

Extensions

------------------------------------------------------------

This API has been designed for ALL implementations and versions of the

Windows environment from and including version 3.0. It thus provides for

Windows CSV implementations and Windows CSV applications in both 16 and

32-bit operating environments.

Windows CSV makes provisions for multithreaded Windows-based processes. A

process contains one or more threads of execution. In the Win16 non-

threaded world, a task corresponds to a process with a single thread.

All references to threads in this document refer to actual "threads" in

multithreaded Windows environments. In non-multithreaded environments (such

as version 3.0), use of the term thread refers to a Windows process.

The extensions to the Windows environment included in Windows CSV are

provided for maximum programming compatibility between Windows 3.x and

Windows NT and optimum application performance in both environments.

WINCSV can be found in the Software/Data Library by searching on the word

WINCSV, the Q number of this article, or S13714. WINCSV was archived using

the PKware file-compression utility.

Additional reference words: 3.10 softlib WINCSV.ZIP

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkMisc


Windows LUA API for 16 and 32-Bit Windows

Article ID: Q93251

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

WinLUA Overview

---------------

WinLUA defines a standard and consistent API for the 16 and 32-bit

versions of the Microsoft Windows graphical environment. It encompasses a

set of Windows-specific asyncronous notification methods designed to allow

the programmer to take advantage of the message-driven nature of the

Windows graphical environment.

This API has been designed and specified to provide a standard to which

application developers can program and network software vendors can

conform. These API details constitute documentation for application

software developers and a specification for network software vendors.

Network software that conforms to either the WinLUA RUI or WinLUA SLI

specification will be considered "WinLUA compliant."  To be WinLUA

compliant, a vendor must implement 100 percent of the WinLUA RUI or WinLUA

SLI specification. Suppliers of such interfaces shall be referred to as

"WinLUA suppliers."

Applications that are capable of exploiting any WinLUA implementation will

be considered as having a "WinLUA interface" and will be referred to as

"WinLUA applications."

While WinLUA is one of the WinSNA APIs to be standardized for the Windows

environment; it is beyond the scope of this document to deal with other SNA

(Systems Network Architecture) APIs.

Microsoft Windows Graphical Environment and Windows-Specific Extensions

-----------------------------------------------------------------------

This API has been designed for ALL implementations and versions of the

Windows environment from and including version 3.0. It thus provides for

WinLUA implementations and WinLUA applications in both 16 and 32-bit

operating environments.

WinLUA makes provisions for multithreaded Windows-based processes. A

process contains one or more threads of execution. In the Win16 non-

multithreaded world, a task corresponds to a process with a single thread.

All references to threads in this document refer to actual "threads" in

multithreaded Windows environments. In non-multithreaded environments (such

as version 3.0), use of the term thread refers to a Windows process.

The extensions to the Windows environment included in WinLUA are provided

for maximum programming compatibility and optimum application performance.

WINLUA can be found in the Software/Data Library by searching on the word

WINLUA, the Q number of this article, or S13713. WINLUA was archived using

the PKware file-compression utility.

Additional reference words: 3.10 softlib WINLUA.ZIP

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkMisc


How to Use WNetGetUser() in Windows for Workgroups

Article ID: Q96772

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Workgroups Software Development Kit (SDK)

   for Windows for Workgroups versions 3.1 and 3.11

----------------------------------------------------------------------

SUMMARY

=======

WNetGetUser() is documented on page 194 in the Microsoft Windows Device

Driver Kit (DDK) "Device Driver Adaptation Guide" for version 3.1. This

function can be used to retrieve the current user name of the user logged

on to the network underlying Windows. However, when using this function in

Microsoft Windows for Workgroups, WNetGetUser() returns WN_SUCCESS but the

user name string is empty. Because WFWNET.DRV is a multinet driver, the

network that supports WNetGetUser() must be activated before using this

function.

MORE INFORMATION

================

Until the release of the Windows for Workgroups SDK, WNetGetUser() was used

internally by Windows. It is documented in the version 3.1 "Device Driver

Adaptation Guide" for network device driver developers. Now, the Windows

for Workgroups SDK allows you to call WNetGetUser() from an application;

however, when using this function on a system with a multinet driver, the

supporting network must be activated first using MNetSetNextTarget(). If

the target network has not been set, the function returns WN_SUCCESS but

the returned string for the user name is empty. This is documented in the

description of MNetSetNextTarget() in the Windows for Workgroups SDK.

It is not sufficient to just call MNetSetNextTarget() before WNetGetUser().

The current target network may not support WNetGetUser(). To properly set

the target network to use WNetGetUser(), the networks must be enumerated

and WNetGetUser() called for each network. If WNetGetUser() does not return

WN_SUCCESS, then enumerate the next target network and iterate this loop.

If the loop iterates through all of the networks but WNetGetUser() never

returns WN_SUCCESS, then none of the target networks support WNetGetUser().

The following sample code demonstrates how to do this:

Sample Code

-----------

/* Compile options needed:  /Gsw /Zp

   Link options needed:     /AL:16 /NOD

*/

BOOL MultiNetGetUser (LPSTR lpszUserName);

{

   HANDLE hNetDrv;

   WORD wRetEnum, wRetGetUser;

   WORD cb;

   hNetDrv = 0;

   wRetEnum = MNetNetworkEnum(&hNetDrv);

   while (wRetEnum == WN_SUCCESS)

   {

      MNetSetNextTarget(hNetDrv);     // activate that network

      wRetGetUser = WNetGetUser(lpszUserName, &cb);

      if (wRetGetUser == WN_SUCCESS)

      {

         MessageBox(NULL, lpszUserName, "WNetGetUser", MB_OK);

         return TRUE;                    // we're done

      }

      // otherwise, try the next one for WNetGetUser support

      wRetEnum = MNetNetworkEnum(&hNetDrv);

   }

   MessageBox(NULL, "WNetGetUser not supported\r\n"

                    "on any of the Multinet subnets", "Error", MB_OK);

   return FALSE;

}

To determine whether a system supports multinet operations, WNetGetCaps()

can be used with WNNC_NET_TYPE. The return value has the WNNC_NET_MultiNet

(0x8000) set if the system supports multinet operations.

Additional reference words: 3.10 3.11 username multi-net

KBCategory: kbnetwork kbprg

KBSubcategory: NtwkWinnet


How to Determine Whether Windows for Workgroups is Running

Article ID: Q114470

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Windows for Workgroups SDK version 3.11

----------------------------------------------------------------------

SUMMARY

=======

Historically, a Windows program could distinguish versions of Windows by

using GetVersion(). However, Windows for Workgroups (WFW) 3.1 was

introduced after Windows 3.1, yet it contains the same version number as

Windows 3.1. This was done because WFW 3.1 is Windows 3.1, but with some

additional DLLs and VxDs for the network support. Note that there has been

a second release of WFW, which is version 3.11. This means that if

GetVersion() returns version 3.1, there is no way to determine whether the

operating system is Windows or WFW. If the version returned is 3.11, then

the operating system is WFW.

While there is no Windows 3.1 API which can be used to absolutely determine

which of these operating systems is running, it is possible to make this

determination. This article describes a method which can be used.

MORE INFORMATION

================

In order to determine whether or not Windows for Workgroups is running when

GetVersion() returns version 3.1, the first step is to see if WNetGetCaps()

is present. If it is, call it to check if there is a multinet driver

installed.

If there is, then the system is Windows for Workgroups. The following code

sample demonstrates this:

   #define WNNC_NET_MultiNet           0x8000

   #define WNNC_SUBNET_WinWorkgroups   0x0004

   #define WNNC_NET_TYPE               0x0002

   HINSTANCE hModInst      = NULL;

   FARPROC   lpWNetGetCaps = NULL;

   WORD      wNetType;

   hModInst = LoadLibrary( "USER.EXE" );

   if( !(lpWNetGetCaps = GetProcAddress( hModInst, (LPSTR)"WNetGetCaps")) )

      MessageBox (hWnd, "WNetGetCaps Not Found", NULL, MB_OK);

   else

   {

   // Get the network type

      wNetType = (*lpWNetGetCaps) (WNNC_NET_TYPE);

      if( wNetType & WNNC_NET_MultiNet )

      {

      // a multinet driver is installed

         if( LOBYTE(wNetType) & WNNC_SUBNET_WinWorkgroups )

         // It is WFW

            MessageBox( hWnd, "Windows for Workgroups", NULL, MB_OK);

         else

         // It is not WFW

            MessageBox( hWnd, "Not Windows for Workgroups", NULL, MB_OK);

      }

   }

   // Clean up the module instance

   if( hModInst )

      FreeLibrary( hModInst );

Additional reference words: 3.10

KBCategory: kbnetwork kbprg

KBSubcategory: NtwkMisc


Windows for Workgroups SDK

Article ID: Q115764

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Workgroups Software Development Kit (SDK)

   for Windows for Workgroups, versions 3.1 and 3.11

----------------------------------------------------------------------

SUMMARY

=========

The Windows for Workgroups (WFW) SDK contains additional files

that can be used with the Windows version 3.1 SDK for WFW development.

The WFW SDK includes the following components:

 - WFW SDK API Help file

 - Header (.H) files

 - Library (.LIB) files

 - Sample code

 - WFW debug binaries

 - WFW WDEB386.EXE files (WFW kernel mode debugger)

The WFW SDK is available on the Microsoft Developer's Network (MSDN)

Level 2 CD set, beginning with the April 1994 edition.

MORE INFORMATION

================

The WFW SDK provides headers, libraries, and help for APIs in the

following areas (which are new with WFW):

 - Networking:

    - WNet (connecting, browsing, sharing)

    - MNet (multiple-network driver interface)

    - Mailslots

    - Named pipes (asynchronous reads and writes)

 - NetDDE (networked DDE)

 - File Manager extensions

 - Common controls

The following are the WFW SDK samples and what they do:

 - MSLOT demonstrates the Mailslot APIs.

 - NPCLNT16 demonstrates the asynchronous named pipe APIs.

 - WFWAPI (in the NETAPI directory) demonstrates various WNet and MNet

   APIs.

 - DDESHARE (in the NETDDE directory) demonstrates the NDde APIs. This is

   the source code to the DDESHARE utility included with the WFW Resource

   Kit.

Additional reference words: 3.10 3.11 NDDE MSDNL2

KBCategory: kbnetwork kbprg

KBSubcategory: NtwkMisc


PRB: Error 6 RPC_S_PROTSEQ_NOT_SUPPORTED in 16-bit Application

Article ID: Q124877

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When trying to run a 16-bit RPC application, the

RpcBindingFromStringBinding() may return error number 6. In the RPCERR.H

file, this is defined as:

   RPC_S_PROTSEQ_NOT_SUPPORTED

CAUSE

=====

Unlike Windows NT, the 16-bit environments do not automatically install

the RPC runtime files and drivers. If the driver for the protocol

sequence your are using is not installed, or is not in your path,

RpcBindingFromStringBinding() will fail with error code 6.

RESOLUTION

==========

The 16-bit RPC runtimes and drivers ship with the Win32 SDK. You can

install them from the CD by going to the \mstools\rpc_dos\disk1

directory on the CD and running setup. By default, the installation

should install all drivers. If you want to verify that, choose the

custom install option.

After the drivers are installed, you will need to make sure that they

are in your path before attempting to run a 16-bit RPC application.

NOTE: You must install the 16-bit drivers even if you are running your

16-bit application on a Windows NT host.

MORE INFORMATION

================

Windows drivers have the extension .DLL and DOS drivers have the

extension .RPC. The driver names and the protocol sequence they support

are as follows:

   rpc16c1    - Named Pipes

   rpc16c3    - TCP/IP

   rpc16dg3   - UDP/IP

   rpc16c4    - DEC Net

   rpc16c5    - NetBIOS

   rpc16c6    - SPX

   rpc16dg6   - IPX

REFERENCES

==========

The "Installing RPC" section of the RPC Programmer's Reference.

Additional reference words: 3.10

KBCategory: kbnetwork kbprg

KBSubcategory: NtwkRpc


How to Perform Programmatic Logon from Windows for Workgroups

Article ID: Q131202

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   for Workgroups version 3.11

 ----------------------------------------------------------------------

SUMMARY

=======

I_AutoLogon is the only documented API for doing a programmatic logon from

Windows for Workgroups. This API requires the user to type a user name and

password. There aren't any other documented functions for performing

logons. In particular, there is no documented to:

 - Perform a programmatic logon using a specific user name and password.

 - Perform a programmatic logon to a particular domain.

MORE INFORMATION

================

It is possible to perform a logon in an indirect fashion by executing a

batch file that calls NET LOGON. For example, you might have a file named

LOGON.BAT that contains:

   REM batch file that performs a logon

   NET LOGON <username> <password> /DOMAIN:<mydomain>

You can use WinExec to execute the batch file:

   WinExec( "LOGON.BAT", SW_HIDE );

REFERENCES

==========

For more information, please see the Windows for Workgroups SDK Help file.

Additional reference words:

KBCategory: kbnetwork

KBSubcategory: NtwkMisc


NetUserPasswordSet Uses NERR_PasswordTooShort for Other Things

Article ID: Q131226

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - LAN Manager 2.1 Programmer's Toolkit

----------------------------------------------------------------------

SUMMARY

=======

When the NetUserPasswordSet LanMan API is called from a downlevel client to

change a password on a Windows NT server, the error NERR_PasswordTooShort

may be returned for error conditions other than the password being too

short.

MORE INFORMATION

================

On Windows NT and Windows 95, the error ERROR_PASSWORD_RESTRICTION (1325)

is returned if a new password is too short, a password is blank when a

password is required, a password does not meet the complexity criterion, a

password is longer than 14 characters, or a password is being reused

without meeting password history requirements. For downlevel systems,

Windows NT must map the ERROR_PASSWORD_RESTRICTION error code to one of the

existing LAN Manager error codes. Because there is no comparable LAN

Manager error, on Windows NT 3.1, ERROR_PASSWORD_RESTRICTION was mapped to

ERROR_UNEXP_NET_ERR (59). On Windows NT 3.5 and later,

ERROR_PASSWORD_RESTRICTION is mapped to NERR_PasswordTooShort (2245).

Additional reference words: 2.10 3.10 PTK LANMAN NETWORK

KBCategory: kbprg

KBSubcategory: NtwkLmapi


MS-DOS-Based RPC Application Cannot Use TCP/IP

Article ID: Q131459

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit(SDK) for Windows,

   version 3.11

---------------------------------------------------------------------

SUMMARY

=======

An MS-DOS-based (16-bit) RPC application cannot use TCP/IP as the protocol

sequence when running under Windows for Workgroup 3.11 with Microsoft's

TCP/IP-32 driver or Windows NT's WOW layer.

MORE INFORMATION

================

MS-DOS-based RPC applications that use TCP/IP as the protocol sequence to

communicate are designed to run only over Microsoft's real mode TCP/IP

driver for Microsoft LAN Manager client software for MS-DOS or any other

compatible real-mode TCP/IP driver implementation.

Windows for Workgroup's TCP/IP-32 protocol driver and Windows NT's WOW

layer do not provide the same real-mode interface for TCP/IP as provided by

the Microsoft LAN Manager TCP/IP driver.

When an MS-DOS-based RPC application tries to use TCP/IP as the protocol

sequence under Windows for Workgroups with Microsoft's TCP/IP-32 driver or

Windows NT's WOW layer, RPC run time report exception 27(0x1b).

Additional reference words: LanManager

KBCategory: kbprg kbnetwork

KBSubCategory: NtwkRpc


Format for Strings and Longs in RCDATA in RC

Article ID: Q28905

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Numbers in the RCDATA section are formatted as documented, with the

additional ability to specify long numbers with an "L" suffix. Strings are

enclosed in double quotation marks ("), and are not null terminated. The

following special mappings are performed:

   Characters  Result      Example

   ------------------------------------------------------------------

   ""          "          """Hello "" there"""  ==> "Hello " there"

   "'"         '

   "\\"        \

   "\t"        TAB

   \011        TAB

   ^I          TAB

   "\a"        Backspace

   \010        Backspace

   ^H          Backspace

   "\x12"      HEX byte 0x12

   "\123"      OCTAL byte 0123

   "\123"      HEX byte 0x53

NOTE: \" is not allowed. Single backslashes ("\") before any other

character are ignored. Nulls are not allowed anywhere in strings. Rather

than using:

   "A string.\0"

use the following:

   "A string.",0

Longs and ints cannot be directly represented inside a string. They must be

built up one byte at a time, or outside any strings.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsRc


Meanings of Resource Compiler Messages

Article ID: Q37532

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows

   versions 3.1 and 3.0.

----------------------------------------------------------------------

The following describes what the RC compiler is telling you in its output

when it is writing resources

   <id>.<Predefined resource type> <bytes>

where <id> is the #define that you give a resource or the string in

uppercase; <predefined resource type> is one of the following

   #define CURSOR        1

   #define BITMAP        2

   #define ICON          3

   #define MENU          4

   #define DIALOG        5

   #define STRING        6

   #define FONTDIR       7

   #define FONT          8

   #define ACCELERATORS  9

   #define RCDATA       10

and <bytes> is the size of the resource.

NOTE: In order to have the output described above generated, you must use

the -v (verbose) switch for the resource compiler when binding a resource

to an executable.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsRc


PRB: Error L2028: Automatic Data Segment Plus Heap Exceed 64K

Article ID: Q43177

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The following error is received during linking:

   L2028: Automatic data segment plus heap exceeds 64K

CAUSE

=====

The LINK error L2028 is caused when the data segment required by the

application exceeds 64K. This can be calculated by adding the HEAPSIZE

and STACKSIZE portions of the .DEF file, plus the global data and

static data. These two numbers of the .DEF file plus the size of the

global and static data need to be under 65536 bytes. The global data

refers to global variables in an application, not the global heap.

RESOLUTION

==========

The solution is to reduce the amount of the HEAPSIZE, STACKSIZE,

global data, or static data. If the application utilizes large amounts

of global data, some of this data should be moved into the memory

covered by Windows [e.g. utilizing GlobalAlloc()]. If the data

consists of constants, such as string tables, these can be moved into

Windows resources using the RC compiler.

This problem may also be resolved by using the /Gt compile option which is

available beginning with the Microsoft C/C++ 7.0 compiler. Using the /Gt

switch, you can specify the size a static object and allocate the static

object its own data segment. If need be the threshold value can be adjusted

to ensure some of the data objects are allocated in an additional data

segment, outside of the default data segment. The default threshold value

when the /Gt option is not specified will be 32767 bytes.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: TlsMisc


Executable Modules Must Be Processed by Resource Compiler

Article ID: Q43295

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The Resource Compiler (RC.EXE) must process each executable module

developed for the Microsoft Windows environment. This requirement

applies both to applications and to dynamic-link libraries (DLLs).

Failure to process an executable module with RC can cause problems

because Windows will use "previous version compatibility" behavior for

that application. Windows versions 3.0 and 3.1 display a warning

dialog box when the user launches an unmarked application.

MORE INFORMATION

================

An application should be processed by RC, even if it does not have any

resources. In versions of Windows earlier than 3.0, it was common

practice to create a null resource file containing only a comment to

provide RC with acceptable input. The RC provided with Windows versions

3.0 and 3.1 supports marking an application that has no resources with

the following syntax:

   RC [switches] module.EXE

RC updates the file header to include the correct version stamp

information. The switches parameter is optional. One switch is -T

which marks an application as running only under protected mode

Windows. Additional switches are listed in the Microsoft Windows

Software Development Kit (SDK) documentation.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsRc


PRB: RCPP.EXE Error: Compiler Limit: Macro Expansion Too Big

Article ID: Q43369

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The Windows Resource Compiler produces the following error message:

   ~rc1234.tmp(145) : FATAL : compiler limit : macro expansion too big

   EXEC Failed - make sure RCPP.EXE is installed correctly.

This error message may be encountered when you are using a "chaining"

technique to define the identifiers for strings that are located within a

stringtable in your resource file.

The identifiers are defined in an include file. "Chaining" means that the

value of an identifier depends on the value of the previous identifier plus

a predefined increment. The following is an example:

#define  ID_START    100

#define  ID_INC      1

#define  ID1         ID_START

#define  ID2         ID1 + ID_INC

#define  ID3         ID2 + ID_INC

#define  ID4         ID3 + ID_INC

#define  ID5         ID4 + ID_INC

   :      :                     :

   :      :             :

  etc    etc           etc

The advantage of this "chaining" technique is that when identifiers are

added, it ensures that every identifier will be unique.

CAUSE

=====

This problem is occurring because the RC compiler does not do mathematical

computation. The lines of code above would actually be expanded as follows:

======== Original code ========  =========== EXPANDED CODE ========

#define  ID_START    100         100

#define  ID_INC        1         1

#define  ID1    IDSTART          100

#define  ID2    ID1 + ID_INC     100 + 1

#define  ID3    ID2 + ID_INC     100 + 1 + 1

#define  ID4    ID3 + ID_INC     100 + 1 + 1 + 1

etc.

What is happening is that after so many lines, the expansion of the line is

exceeding the buffer allotted for macro expansions. Since the RC compiler

does not do arithmetic, it interprets all #defines as characters.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb kbcode

KBSubcategory: TlsRc


Using the Linker /ALIGN Option

Article ID: Q47493

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article discusses various considerations regarding the Microsoft

Linker and its /ALIGN option when it is used to develop applications

for the Microsoft Windows environment. This information also applies

to the development of dynamic-link libraries (DLLs) for Windows.

MORE INFORMATION

================

According to its definition, the Microsoft Linker /ALIGN option

"directs the linker to align segment data in the executable file along

the boundaries specified by 'size.'" The "size" parameter is in bytes

and must be a power of 2. Specifying /ALIGN:16 on the LINK line aligns

segments on 16-byte boundaries. Making an /ALIGN:16 specification is

recommended for Windows-based applications and dynamic-link libraries

(DLLs) because the default alignment is 512.

When the linker creates an EXE file and /ALIGN:16 is specified, if a

segment does not end on a 16-byte boundary, the segment is padded with

extra bytes. The next segment always begins at a 16-byte boundary.

If an application contains several small segments, and no /ALIGN

option is specified on the Linker command line, each segment will

contain a great deal of wasted space and the resulting EXE file will

be unnecessarily large. The amount of wasted space is computed as

follows:

   waste = align - (segment modulo align)

Therefore, for a 514-byte segment, an align size of 512 causes 510

bytes to be wasted. However, for the same segment, an alignment size

of 2 bytes does not waste any space.

Problems can arise when the Linker creates a very large EXE file using

a small align value because the size of the EXE may exceed the range

of values that can be represented by the EXE header segment table.

To demonstrate the problems that can arise, consider a very large EXE

file that is linked with an align size of 2. During the process of

creating this EXE file, the Linker puts segment 42 at file offset

380,000 and records the position in the New EXE Segment Table. The

format of this table is as follows:

   Offset  Length  Contents

   ------  ------  --------

      0h      2    Offset of segment relative to beginning of file

                   after shifting value left by alignment shift count.

      2h      2    Length of segment (0h for segment of 65536 bytes).

      4h      2    Segment flag word.

      6h      2    Minimum allocation size for segment; that is,

                   amount of space Windows reserves in memory for the

                   segment (0h for minimum allocation size of 65536

                   bytes).

In this case, the offset of the segment to place in the table is

(380,000 >> 1) = 190,000, which is too large to store in a 16-bit word

(the maximum value is 65,535). Therefore, 58,928 (the low-order 16

bits of 190,000) is stored. Unfortunately, the Linker does not provide

any warning of the data loss involved with this step.

When Windows loads segment 42 from the EXE file, it takes the value

58,928 and multiplies it by the align size (2), which results in an

offset of 117,856 and does not lead to the desired segment in the

file.

For more information on the new .EXE (New Executable) file header format,

see appendix K (pages 1488-1497) of the "MS-DOS Encyclopedia" (Microsoft

Press). Also refer to the article "Liposuction Your Corpulent Executables

and Remove Excess Fat" by Matt Pietrek in the Microsoft Systems Journal,

vol. 8, no. 7, July 1993 which describes a sample tool called EXESIZE.

Please call the publishers (Miller Freeman Inc.) at (800) 666-1084 for

order information.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsMisc


Developing Common Code for Both Windows and Macintosh

Article ID: Q48023

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

We are not aware of any kind of Windows-to-Macintosh interpreter or

translator that will allow you to directly run Windows code on the

Macintosh, but there are some alternatives:

1. The January 1989 issue of the "Microsoft Systems Journal" contains

   two relevant articles titled "Developing Applications with Common

   Source Code for Multiple Environments" and "Porting Apple Macintosh

   Applications to the Microsoft Windows Environment."

2. The "Windows Developer Guidebook" [available by calling

   (800) 426-9600] contains a listing for a product that helps you

   develop code in an environment-independent way. The product is

   called XVT (Extensible Virtual Toolkit) for Microsoft Windows,

   Presentation Manager, and Macintosh. XVT is made by the following

   company:

      GSS (Graphical Software Systems)

      9590 SW Gemini Drive

      Beaverton, OR  97005

      (503) 643-8642

   According to GSS, "XVT allows developers to create and maintain one

   set of source code and port it to Windows, PM, and Macintosh

   environments."

3. A third-party product called CommonView contains Glockenspiel C++

   object libraries to simplify creation of applications for Windows

   and OS/2 Presentation Manager (PM) using the same core source code.

   Contact the company to find out more about porting to the Macintosh.

   CommonView is a set of class libraries for creating Microsoft

   Windows and PM applications. They come with the C++ compiler, which

   is an object-oriented version of C. They are actually translators

   that translate C++ code into C code, which you can then run through

   your C compiler. You can write an application using CommonView, and

   it will isolate you from the particular Windows environment. A

   demonstration of CommonView is available on CompuServe in LIB 6

   (windows). The product is distributed by Imagesoft, (800) 245-8840

   or (516) 767-2233.

XVT and CommonView are manufactured by vendors independent of

Microsoft; we make no warranty, implied or otherwise, regarding these

products' performance or reliability.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsMisc


WDEB386 Debugger's Use of COM Port

Article ID: Q58010

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The only COM port setting for the Windows 80386 Debugger (WDEB386)

that can be altered through the /C: command-line switch is the

specification for which COM port to use. (The COM port and the baud

rate can also be changed through a debugger command.) Unlike CodeView,

WDEB386 runs outside the Windows environment and does not use WIN.INI

or SYSTEM.INI settings to store its configuration.

WDEB386 reprograms the COM port before it sends each character. This

feature prevents other programs or parts of programs that use or abuse

the COM port, such as the MS-DOS MODE command, from influencing the

operation of WDEB386. This prevents misbehaving applications from

affecting communication with the debugger.

WDEB386 is a systems-level debugger for the Windows version 3.0

protected mode environment (enhanced mode and standard mode). Because

it can debug the initialization portion of device drivers that run

under protected mode Windows, WDEB386 is often used during device

driver development. However, for most uses, CodeView is the preferred

protected mode debugger.

In Windows version 3.1, WDEB386 adds the /R: command-line switch to

specify the baud rate.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsWdeb


PRB: Encountering an INT 01 with WDEB386

Article ID: Q64123

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When debugging an application with WDEB386, the program halts on a

breakpoint at an INT 01 instruction.

CAUSE

=====

An INT 01 is coded into Windows in the Fatal_Error_Handler. This interrupt

is hit when some device driver is doing a fatal exit. The INT 01 is there

to make the debugger useful when diagnosing the fatal error. INT 01 in

virtual devices (VxDs) is generally ignored (treated as a NOP instruction)

in the retail version of Windows. However, if the debugger is installed,

the system breaks into the debugger.

RESOLUTION

==========

Diagnose and correct the cause of the fatal exit.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: TlsWdeb


PRB: C Pragma Comment & #ident Strings Missing from Executable

Article ID: Q65979

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

After compiling an application developed for Windows version 3.0 or 3.1

from code that uses the comment pragma feature or the #ident preprocessor

directive of the Microsoft C Compiler, the comment string is missing from

the final executable file.

CAUSE

=====

The Resource Compiler in the Windows Software Development Kit (SDK) version

3.0 or 3.1 removes the comment string from the executable.

RESOLUTION

==========

Declare the comment as a static string variable, as follows:

   static char CommentString[] = _FILE_" = $Revision:   1.2   $";

This will embed the desired information in the .EXE file; however, when the

program is run, the application will load the string with the program's

other variables. This will take up some storage in the local data space.

MORE INFORMATION

================

This behavior is an unavoidable consequence of the method the Microsoft C

compiler uses to store comment strings in an executable file. Placing the

strings outside all segments is not consistent with the Windows segment-

executable format, which places all code and data into segments that can be

loaded separately. The Resource Compiler cannot preserve comment data

stored outside any segment.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsRc


Windows-Based Application Installation Sample Code

Article ID: Q66395

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

WINSET2 is a file in the Microsoft Software Library that contains the

source code necessary to create a Windows-based application installation

program. This program does the following:

1. Prompts the user for a directory into which to install the

   application.

2. Checks for available disk space.

3. Creates directories as needed.

4. Copies the files from the installation source (the program will

   expand compressed files during the copy process, if necessary).

5. Adds icons to a Program Manager group if the Program Manager is the

   current shell program.

This program does not detect system hardware, and is designed to

install applications on an already existing Windows system.

Download WINSET2.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINSET2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINSET2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINSET2.EXE

MORE INFORMATION

================

The WINSET2 file contains an internal directory structure. The PKware

file extraction utility has a -D option switch that creates the

corresponding directory structure on the destination disk.

The following files are part of WINSET2:

BINCODE Directory

    BINCODE     : Debug build NMAKE file (Microsoft C version 6.0)

    BINCODE.C   : BINXZ main code

    BINCODE.DEF : DEF file for BINXZ

    BINCODE.DLG : Dialog templates

    BINCODE.H   : BINXZ header file

    BINCODE.ICO : Setup icon

    BINCODE.MAK : Debug build MAKE file (Microsoft C version 5.1)

    BINCODE.RC  : Resource template

    BINCODE1.H  : BINXZ header file (describes resources)

    BINRET      : Retail build NMAKE file (Microsoft C version 6.0)

    BINRET.MAK  : Retail build MAKE file (Microsoft C version 5.1)

    DIALOGS.C   : Dialog box routines

    DOS.ASM     : Low-level MS-DOS routines in ASM

    EXPAND.LRG  : File decompression module, large model

    EXPAND.MED  : File decompression module, medium model

    EXPAND.SML  : File decompression module, small model

    GASGAUGE.C  : Gas gauge code file

    GASGAUGE.H  : Gas gauge header file

    IO.C        : Low-level MS-DOS routines in C

    PARSE.C     : INF file parser

    PROGDDE.C   : Program Manager dynamic-data exchange (DDE) routines

    SETUP.INF   : Sample SETUP.INF file

NOTE: Due to U.S. Government rules regarding the exporting of encryption

technologies, EXPAND.C cannot be distributed.

COMPEPND Directory

    COMPRESS.EXE: MS-DOS-based file compressor

    EXPAND.EXE  : MS-DOS-based file uncompressor

NOTE: It is a good idea to provide the EXPAND utility with the installed

application. This allows users to access the files on the distribution

disks.

SETUP Directory

    SETUP       : NMAKE file (Microsoft C version 6.0)

    SETUP.C     : Setup stub loader source

    SETUP.DEF   : DEF file

    SETUP.MAK   : MAKE file (Microsoft C version 5.1)

The following tools are required to build and use WINSET2:

- Windows Software Development Kit version 3.0 or later

- Windows version 3.0 or later

- Microsoft C version 6.0 or later

- Microsoft Macro Assembler version 5.1 or later

- MS-DOS version 3.1 or later

The Contents of a Release Setup Disk

------------------------------------

The Setup program has two components, SETUP.EXE and BINXZ.EXE. Setup

spawns BINXZ, which actually performs the installation. If Setup

determines that it is running from a floppy disk, it will copy BINXZ

to the Windows directory on the user's hard disk. BINXZ will run

itself from the hard disk and delete itself when done. (BINXZ deletes

itself only if it is copied by Setup. If the file is already on the

hard disk, it will remain.)

Because Setup copies BINXZ to the hard disk, the program can use

traditional Windows programming methods (using movable, discardable

segments) and still allow the user to change disks in Drive A without

disrupting the process.

The first disk must contain files as follows:

   A:\SETUP.EXE

   A:\SETUP.INF

   A:\BIN\BINXZ.EXE

If Setup will be run from a hard disk or from a network, preserve the

contents of the BIN directory. Setup will run from a network or a hard

disk.

All files involved with the installation must be in subdirectories of

the "root" installation directory. This is done to prevent the user

from running the application(s) directly from the Setup disk.

The Contents of an Example Sample Disk

--------------------------------------

   A:\SETUP.EXE

   A:\SETUP.INF

   A:\BIN\BINXZ.EXE

   A:\BIN\SOL.EXE

   A:\BIN\REVERSI.EXE

   A:\DLL\SOL.DLL

   A:\DLL\REVERSI.DLL

   A:\HLP\SOL.HLP

   A:\HLP\README.TXT

The SOL.* files comprise one application. The user has the option to

install these files. The REVERSI.* files comprise a second

application. The user has the option to install these files. The

README.TXT file is required; the user does not have the option to omit

installing this file.

Setup shields the user from manually selecting SOL.EXE, SOL.DLL, and

SOL.HLP. Instead, the user chooses "Solitaire Game" and the system

does the necessary mapping to install the following three files:

   \BIN\SOL.EXE

   \DLL\SOL.DLL

   \HLP\SOL.HLP

The "nn" field in the [apps] section of SETUP.INF provides the

mechanism to do this. Arbitrarily choose one of the three files, for

example SOL.EXE, to be the "main" file. The other two files are marked

to depend on the main file. When the user chooses to install the main

file, Setup copies all three files to the hard disk. In this example,

the "nn" field for SOL.EXE would be 02, to indicate that the next two

files depend on SOL. These files must be listed sequentially in the

SETUP.INF file.

When the Solitaire application is installed, Setup can create an icon

for it in the Program Manager. Each icon must reside in a group.

Because an application cannot request the list of active groups from

the Program Manager using dynamic-data exchange (DDE), the Setup

program always creates a new group. The following lines in SETUP.INF

define a group called "A":

    [progman]

       "A","Solitaire Application","SOL.GRP"

The "Ic" field in the [apps] section specifies the group where the

icon will be placed. "IA" places the SOL.EXE icon into group "A."

Because the user has the option to install SOL.EXE, the "D" flag in

the [apps] section is also specified. In the "complex" version of

Setup, this flag adds the application to the Select list box and

allows the user to choose to install the application.

Each file must be associated with three of strings: the icon title,

the application's description (often the same as the icon title), and

a comment string (approximately 70 characters long). These fields are

appended to the description of SOL.EXE in the [apps] section. Finally,

the sizes of SOL.EXE, SOL.DLL, and SOL.HLP sum to 70 kilobytes. This

is indicated by the "70" size field at the end of the description.

The Solitaire entry in [apps] section of SETUP.INF will resemble the

following:

   "0","02DIA","0","BIN","SOL.EXE","Solitaire","Solitaire","The most

tested application ever!","70"

   "0","",     "0","DLL","SOL.DLL"

   "0","",     "0","HLP","SOL.HLP"

For an uncompressed file, the line in the [apps] section is as

follows:

    X   flags   Y    Z   filename  icon title app title

    v  /     \  v  /   \ /       \ /       \  /        \

   "0","02DIA","0","BIN","SOL.EXE","Solitaire","Solitaire","The most

tested application ever!","70"

                          \  /

                          size

   The "X" field contains the source disk number.

   The "Y" field contains the destination directory number.

   The "Z" field contains the source and destination directory names.

A compressed file is very similar, adding a "C" to the flags field, as

follows:

   "0","C02DIA","0","BIN","SOL.EXE","Solitaire","Solitaire","The most

tested application ever!","70"

The information for REVERSI.EXE is similar to that used above.

However, because REVERSI does not receive a Program Manager icon, the

"IA" flag is not specified.

Because the README.TXT file is required, its line resembles the

following:

   "0","R","0","HLP","README.TXT","Read Me","Read Me","","1"

The Remainder of the SETUP.INF File

-----------------------------------

There are three other sections in the INF file: [setup], [disks], and

[directories]. The following sections provide some tips regarding

these sections.

The [setup] section provides additional information about the Setup

program.

"PACKAGENAME","Solitaire"

   SETUP refers to the application it is installing by using the

   PACKAGENAME variable. This variable should contain the name of the

   product as it is listed on the packaging.

"CAPTIONNAME","Solitaire Setup"

   This caption is used by the Setup program in all of its dialogs.

   This variable usually contains the PACKAGENAME followed by "Setup."

The [disks] section provides information about the Setup source disks.

"0","A:\","SOL Setup Disk #1"

   This line indicates that disk #0 is called "SOL Setup Disk #1," and

   that it will be located in Drive A, by default. If Setup cannot

   find any files, it will also check the directory from which Setup

   was run (a network drive, a hard disk, or Drive B, as

   appropriate). After searching this drive, if Setup is still unable

   to find the file, it will prompt the user to insert "SOL Setup Disk

   #1."

The [directories] section provides information about the destination

directories.

"0","C:\SOL","Solitaire App Dir"

   This line specifies the "main" directory. This line must be present

   in the SETUP.INF file. This directory is presented as the default

   when Setup prompts the user where files should be installed. This

   must be directory "0."

"A","\CHILD1","Solitaire Directory Child 1"

   Setup builds child directories from the "main" directory. Valid

   child directory names are "A"-"Z."

Comments about the Source Code

------------------------------

The Setup program is designed to provide the maximum flexibility with

minimum modifications to the source code. However, many applications

require special functionality and some features that this code does

not provide. Some useful features that this code does not provide

include the following:

- Modifying the AUTOEXEC.BAT, CONFIG.SYS, or profile (INI) files. The

  code to implement this functionality can be modeled on the code in

  PARSE.C, which retrieves information from the SETUP.INF file. The

  process of adding a new data structure to the SETUP.INF file for

  this additional data should be quite straightforward.

- Determining system hardware. Setup is meant to be run on an

  installed copy of Windows. It does not install Windows. Therefore,

  standard Windows calls such as the GetSystemMetrics function should

  be used to determine the system hardware.

Additional reference words: 3.00 3.10 softlib WINSET2.EXE setup

installation share invalid media

KBCategory: kbtool kbfile

KBSubcategory: TlsMss


Help Compiler Internal Error Possible Causes

Article ID: Q66494

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The explanation of errors R2701 through R2709 is "Internal error," and the

user is directed to contact Microsoft Product Support Services for

clarification. This article contains information on these internal

errors.

MORE INFORMATION

================

The list is:

R2701:  Creation of title b-tree has failed

R2703:  Creation of bitmap file has failed.

These two file creation failures can happen due to low memory, low disk

space, or lack of file handles.

R2705:  Phrase file does not exist.

This error is given if the phrase file mysteriously disappears between the

time it was created (or checked for existence) and when it is used. It

might be caused by low disk space, or from compiling on the network.

R2707:  Closing of file has failed.

This is a disk error that is not out of memory, out of disk space, or out

of file handles. It might indicate hard disk problems such as bad sectors,

or too many files in one directory.

R2709:  Opening output system file failed.

If someone does encounter this error, they are using an old Beta version.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsHlp


Windows SDK Support for Microsoft FORTRAN Compilers

Article ID: Q66632

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Using the Microsoft FORTRAN Optimizing Compiler versions 5.0 and

earlier to compile Windows programs is not supported. The Windows SDK

support is limited to support of the Microsoft C Compiler and Microsoft

Macro Assembler (MASM).

To compile Windows programs, use the Microsoft FORTRAN Optimizing Compiler

version 5.1 or later. This version includes the necessary libraries to

compile code to run under Windows version 3.0 in standard and enhanced

mode.

MORE INFORMATION

================

The FORTRAN 5.1 compiler includes support for Mixed Language application

and stand-alone QuickWin FORTRAN applications. The FORTRAN PowerStation 32-

bit compiler for MS-DOS does not include support to do mixed language

programming with any Microsoft C/C++ Windows compiler. The FORTRAN

PowerStation compiler for Windows NT does support mixed language

programming for Windows NT. Mixing support is available to mixed projects

using the Visual C++ for Windows NT compiler.

The most important reason why FORTRAN version 5.0 routines will not work

under Windows is that the FORTRAN version 5.0 run-time libraries are not

designed to communicate with Windows; they are designed for either MS-DOS

or OS/2 programming. The Windows SDK includes specially modified versions

of the standard C run-time libraries that are designed for Windows

programming. A standard FORTRAN version 5.0 library, such as MLIBFORE.LIB,

makes no allowances for Windows programming.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsMisc


Windows Programmer's Reference (Advisor Format)

Article ID: Q69232

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows version 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following is the complete contents of the application note titled

"Windows Programmer's Reference (Advisor Format)." Application notes

can be obtained by calling Microsoft Product Support Services at

(206) 454-2030.

Windows Programmer's Reference (Advisor Format)

-----------------------------------------------

The Windows Software Development Kit (SDK) provides the information

contained in its "Microsoft Windows Software Development Kit

Reference" manual in two different types of formatted files: the

Windows Help format (used with the Windows Help engine) and the

Advisor format (used with QuickHelp and the Programmer's WorkBench).

The disk that comes with this application note contains a copy of the

Advisor format file that should be used to replace the copy of this

file included with the Windows SDK. The information in the two files

is the same. However, the file included with this application note

will display its table of contents in response to the QuickHelp View

All Tables Of Contents command (from QuickHelp's View menu, choose

View All Tables Of Contents). The file shipped with the SDK does not.

Installing the Revised Help File

--------------------------------

1. Make sure that the Windows SDK is installed.

2. Using the Expand program (which is distributed with the Windows

   SDK), copy the file from the enclosed disk to the Windows

   development directory (by default, this is C:\WINDEV) by entering

   the following command at the MS-DOS prompt:

      expand a:sdkadv.hl$ C:\WINDEV\SDKADV.HLP

Additional reference words: 3.00 appnote PW0287

KBCategory: kbtool kbappnote

KBSubcategory: TlsMisc


Windows Help (HLP) File Format Is Not Available

Article ID: Q69882

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The data formats for ANN and HLP files used by the Microsoft Windows

Help application are under development and are not expected to remain

constant in future versions of Windows Help. To avoid problems with

different versions of these files, Microsoft has decided not to

publish either file format.

Currently, the Microsoft Windows Help Compiler, distributed with

versions 3.0 and 3.1 of the Microsoft Windows Software Development Kit

(SDK) and with other Microsoft applications that produce HLP files, is

the only tool available to generate files compatible with the Windows

Help system.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsHlp


Overcoming "C4071 No Function Prototype Given" Warning

Article ID: Q69898

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

Code that is compiled using the Microsoft C compiler's warning level 3

(/W3) or higher and that calls functions through FARPROC pointers causes

the Microsoft C compiler to report warning C4071, "No Function Prototype

Given."

CAUSE

=====

Pointers to functions are commonly used when an application explicitly

loads dynamic-link libraries (DLLs) through the Windows LoadLibrary

function. Function pointers declared with FARPROC do not inherit function

prototype information.

RESOLUTION

==========

Modify the function pointers declarations to include function prototype

information.

MORE INFORMATION

================

The following code sample uses the generic FARPROC far-pointer-to-function

data type. Compiling the code with Microsoft C at warning level 3 or higher

results in a C4071 warning:

   FARPROC lpfnErrorProc;

   lpfnErrorProc = GetProcAddress(hModule, MAKEINTRESOURCE(1));

   (*lpfnErrorProc)(hWnd, (LPSTR)"Error Message");

However, the following code sample defines custom far-pointer-to- function

data types which provide information about the function arguments. This

code does not produce the warning:

   // typedef declarations

   typedef VOID FAR PASCAL FNERRORPROC(HWND, LPSTR);

   typedef FNERRORPROC FAR *LPFNERRORPROC;

   // variable declaration

   LPFNERRORPROC  lpfnErrorProc;

   // variable assignment and indirect function call

   lpfnErrorProc = GetProcAddress(hModule, MAKEINTRESOURCE(1));

   (*lpfnErrorProc)(hWnd, (LPSTR)"Error Message");

Additional reference words: 3.00 3.10

KBCategory: kbprg kbcode

KBSubcategory: TlsMisc


Corrupt RES File May Crash Dialog Editor

Article ID: Q70072

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

A corrupt RES file may cause the Dialog Editor distributed with the

Windows Software Development Kit (SDK) to crash. If the Dialog Editor

crashes consistently processing a particular file, delete the RES file

created by the Dialog Editor and use the resource compiler to recompile the

DLG dialog script file.

MORE INFORMATION

================

To compile the DLG dialog script file, you must include WINDOWS.H at the

top of the script. You must make the following line the first line in your

DLG file:

   #include <windows.h>

To compile the dialog script file using the resource compiler, use the

following command line:

   rc mydlg.dlg

where "mydlg" is replaced with the name of the dialog script file. This

will produce a RES file that can be used by the Dialog Editor and should

help to alleviate the crashing problems.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsDlg


PRB: SPY Updates Only One Line with Small Buffer

Article ID: Q70889

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When using SPY, only the bottom line of the SPY window is updated as

messages are received.

CAUSE

=====

In the SPY Options dialog, the number of lines to save in the buffer

is smaller than the number of lines that will fit in the SPY main

window.

RESOLUTION

==========

Specify a buffer size larger than the size of the SPY main window.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsSpy


PRB: Resource Compiler Error RW1022 Caused by Temporary File

Article ID: Q71312

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the resource compiler processes a resource script, the following

message is displayed:

   RW1022: I/O error writing file.

CAUSE

=====

The resource compiler creates a temporary file in the directory specified

by the TMP MS-DOS environment variable. There may not be enough room in the

temporary directory to extend this file.

NOTE: This is just one possible cause for the error message; there are

others. The Build Tools help file that comes with Visual C++ discusses some

of them.

RESOLUTION

==========

Make room on the device that holds the temporary files.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsRc


WIN.INI Settings for Windows Help Hypertext Colors

Article ID: Q74283

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The user can control the color that the Microsoft Windows Help

application uses to display hypertext strings by using the JumpColor

and PopupColor settings in the [Windows Help] section of the WIN.INI

file. The JumpColor setting specifies the color for context strings,

and the PopupColor setting specifies the color for definition strings.

Both settings use the following syntax:

   setting=(r,g,b)

where r, g, and b are decimal values in the range 0 to 255 that

specify a color value as a red-green-blue (RGB) triplet.

For example:

   [Windows Help]

   JumpColor=(128,0,0)     ; produces red context strings

   PopupColor=(0,128,128)  ; produces cyan definition strings

The default color for both types of hypertext strings is green.

The Windows Help Compiler documentation in the Microsoft Windows

Software Development Kit (SDK) discusses context and definition

strings in more detail.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsHlp


Information About Headings and Labels in HEAPWALK

Article ID: Q74301

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The Heap Walker utility (HEAPWALK) is a tool used to view the memory

layout in the Microsoft Windows graphical environment. With HEAPWALK,

you can examine memory before, during, and after an application runs

and examine how an application behaves under different memory

conditions. This article lists and explains the columns of information

that HEAPWALK displays for global and local memory objects.

The version of HEAPWALK provided with version 3.1 of the Microsoft

Windows Software Development Kit (SDK) differs significantly from the

version provided with version 3.0. HEAPWALK version 3.1 uses the Tool

Helper dynamic-link library (DLL), displays information in a more

organized manner (by sorting objects based on a secondary key),

provides information about objects in the user heap as well as in the

GDI help, and simultaneously displays a graphical representation of a

resource along with a hex dump of the resource.

The information in this article applies to HEAPWALK versions 3.0 and

3.1 unless otherwise noted.

MORE INFORMATION

================

Main Window

-----------

HEAPWALK displays a list of memory objects in the global heap in its

main window. Options on the Walk menu determine which objects HEAPWALK

displays in its main window. Options on the Sort menu determine the

order in which objects are displayed in the main window. Options on

the Object menu specify a number of actions that HEAPWALK can perform

on a selected object.

For each global memory object, HEAPWALK displays various information

in its main window, as follows:

ADDRESS:

   Address of the memory block (in hexadecimal).

    - In real mode or standard mode, this is a physical address value.

    - In enhanced mode, this is a linear address value. (The paging

      mechanism maps a linear address to a physical address.)

HANDLE:

   Handle for the memory block (in hexadecimal).

    - This value was returned from a GlobalAlloc call.

SIZE:

   Size of the memory block in bytes (in decimal).

LOCK:

   Current lock count of the memory block (displayed only if nonzero).

FLG:

   Flag.

      D - If memory block is discardable.

          Page 11-3 of the "Microsoft Windows Software Development Kit

          Tools" manual for version 3.0 incorrectly states that this

          field contains an "S" for shareable segments. Instead, the

          OBJ-TYPE field contains "Shared" for shareable segments.

OWNER-NAME:

   Owner of the memory block.

    - Usually the module that allocated the memory block.

    - Can be an application name (for example, HEAPWALK), one of the

      Windows modules (USER, GDI, DISPLAY, and so on), or FREE.

OBJ-TYPE:

   Type of memory object:

    - Code segment number or name - Code segment along with its number

        or name. (To display segment names, place the SYM file for the

        application module in the directory from which HEAPWALK runs,

        and select the Label Segments command from the Sort menu.)

    - Data - Data segment.

    - Shared - A shared object.

    - Resource

    - Kernel data structures such as:

       - Task

       - Task Database

       - Module Database

ADD-INFO:

   Additional information that may accompany OBJ-TYPE.

    - This is usually a resource type such as an icon, a cursor, or a

      font.

Local Window

------------

To view the memory objects in an application's local heap, select the

application's data segment and use the Show and LocalWalk commands

from the Object menu. This results in two windows: a Show Window,

which displays a hexadecimal memory dump, and a Local Window, which

displays a list of the local objects and their attributes, as follows:

OFFSET:

   Offset of the local memory block in the data segment (in

   hexadecimal).

SIZE:

   Size of the local object in bytes (in decimal).

MOV/FIX:

   Mov - For a movable memory block.

   Fix - For a fixed memory block.

FLAGS:

   For movable objects.

      D - If discardable.

      Lnn - Lock count if nonzero.

OBJECT TYPE:

   "Free" for free objects.

   For the GDI data segment, the local window displays the object type

       (for example, DC, Brush, Pen, or Region).

Show Window

-----------

Using the Show command from the Object menu displays a hexadecimal

dump of any global memory block in a separate window. The show window

displays the offset, hexadecimal memory dump, and the ASCII memory

dump. The Showbits command displays the memory as a bitmap (if the

block contains a cursor, an icon, or a bitmap).

HEAPWALK version 3.0 truncates objects that are larger than 64K.

HEAPWALK version 3.1 does not exhibit this behavior.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsHeapWalk


PRB: RC Error RW1031: Segment Too Large for Load Optimization

Article ID: Q74411

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When building an application, the Microsoft Windows Resource

Compiler, RC.EXE, reports the error message "Error RW1031: Segment

Too Large For Load Optimization."

CAUSE

=====

The size of an application segment added to the size of the

relocation information for the segment is larger than 64K.

RESOLUTION

==========

Perform one of the following:

 - For optimal performance in the Microsoft Windows graphical

   environment, divide the application's code into units of

   approximately 4K to 8K each.

 - Specify the Resource Compiler -k command-line option switch to

   disable the load optimization feature.

MORE INFORMATION

================

One underlying cause for this Resource Compiler error is an

application developed for the medium or large memory model linked with

the /PACKCODE Microsoft Linker option switch. This option directs the

linker to combine code segments to produce fewer and larger code

segments.

When the Resource Compiler processes an application for load

optimization (its default behavior), it places all application

segments marked PRELOAD into the application's fastload area. The

fastload area is designed to allow the Windows kernel to copy the

initial segments of an application directly from the file on disk into

memory to minimize the amount of time the user must wait before

interacting with the application. The kernel performs minimal

processing on the contents of the fastload area to maximize its

performance benefits; this strategy is incompatible with a large

segment with much relocation information.

By breaking an application into small units, Windows can manage memory

by discarding and reloading segments as necessary. Windows supports

techniques provided by the Microsoft C compiler to name and manually

combine segments and to specify segment attributes through the

application's module definition (DEF) file. In enhanced mode Windows,

it should not be necessary to discard segments; memory is

automatically paged to disk and reloaded as required.

Additional reference words: 3.00 3.10 PACKC

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsRc


"Profiler VM Terminated Abnormally" Message Causes

Article ID: Q74477

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The VPROD.386 device driver displays the message "Profiler VM

terminated abnormally" whenever the virtual machine (VM) being

profiled is terminated (crashed) while profiling is still under way.

Some circumstances under which virtual machines are terminated are:

when a bad instruction is executed, when an attempt is made to program

virtualized hardware in a manner incompatible with the virtualizing

virtual device (VxD), or when the user selects "Terminate" in the

Settings dialog box. In any of these situations, the VPROD device

driver cannot flush its queued profile data and clean up after itself.

The message is displayed when VPROD can no longer simulate MS-DOS calls

into the terminated VM. The message warns that it is highly likely

that profiling data has been lost.

For more information on the Profiler, see chapter 13 of the "Microsoft

Software Development Kit Tools" manual.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsPrf


PRB: Application Not Recognized as Compatible with Windows 3.x

Article ID: Q74490

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When you run an application designed for version 3.0 or 3.1 of the

Windows graphical environment, Windows displays one of the

following error messages:

   The specified application is not based on Windows or MS-DOS.

-or-

   Application Compatibility Warning:

   The application you are about to run, filename.exe, was designed

   for a previous version of Windows.

   You should obtain an updated version of the application that is

   compatible with Windows version 3.0. To run the current version

   of the application, choose Cancel. Then, exit Windows, restart

   it by typing Win /r, and start the application again.

   If you choose OK and continue to start this application, you

   might encounter compatibility problems that could cause the

   application or Windows to terminate unexpectedly.

[The message for Windows version 3.1 is similar. However, it does

not instruct the user to restart Windows in real mode (Win /r)

because real mode is not available.]

CAUSE

=====

The application was not processed by the resource compiler (RC) or

the module definition (DEF) file does not contain the EXETYPE

WINDOWS statement.

RESOLUTION

==========

In the Windows environment, each application and dynamic-link

library must be processed by RC even if it does not have any

resources. RC modifies the file header to enable Windows to process

the application or library correctly.

Running an application that was not processed by RC causes Windows

to display the Application Compatibility Warning message box that

contains the text above.

The DEF file for an application or DLL must contain the EXETYPE

WINDOWS statement to direct the linker to create a Windows EXE

file. If this statement is missing, RC fails with an error such as

the following:

   RC : fatal error RW1030: filename: The EXETYPE of the program is

   not WINDOWS. Make sure the .DEF file is correct.

Attempting to run an improperly-linked application causes Windows

to display an Unrecoverable Application Error (UAE) message box

that contains the first error message listed above.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsRc


Advanced WDEB386 Features and Tips

Article ID: Q74605

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article explains some of the more advanced WDEB386 commands and

features, including:

 - Breakpoint commands (BP/BR)

 - Conditional execution command (J)

 - Default command (Z)

MORE INFORMATION

================

Breakpoint Commands

-------------------

Syntax:

   BP[n] <address> [<passcount>] ["<breakpoint cmds>"]

   BR[n] E|W|R|1|2|4 <address> [<passcount>] ["<breakpoint cmds>"]

A breakpoint command is a string of debugger commands that are

executed when a breakpoint is hit. Semicolons (;) separate commands

from one another. All text is converted to uppercase except for text

surrounded by single quotation marks ('). Two single quotation marks

('') or two double quotation marks ("") in a row act as an escape

character and add one single quotation mark or one double quotation

mark to the string. The maximum length of a breakpoint command is 80

characters. Both normal (set with BP) and 386 debug register (set with

BR) breakpoints can have breakpoint commands.

The commands BP[n] "<breakpoint command>" or BR[n] "<breakpoint

command>", where n is the breakpoint number, can be used to add or to

change commands corresponding to existing breakpoints. Other

breakpoints or the last breakpoint encountered can be set, cleared,

disabled, or enabled.

If the breakpoint has no breakpoint command string, WDEB386 executes

the default (ZD) command. (See below for information about the default

command.) The conditional execution command (J) is very useful in

breakpoint commands (see below).

Conditional Execution Command

-----------------------------

Syntax:

   J <expr> ["<command list>"]

This command executes the command list if the expression evaluates to

TRUE (nonzero); otherwise, it continues to the next command in the

command line (not including the ones in the command list parameter).

If the command list contains more than one command, it must be

enclosed in single or double quotation marks. Use a semicolon (;) to

separate commands. No quotation marks are required if the command list

contains zero or one command. The conditional execution command can be

used in breakpoint commands to halt execution when an expression

becomes true or in the default command (see below).

Any operator, number, or symbol value can be used in the conditional

expression. The following are the most common relational operators

used with this command:

   >    Greater than

   <    Less than

   >=   Greater than or equal to

   <=   Less than or equal to

   ==   Equal to

   !=   Not equal

   &&   Logical AND

   ||   Logical OR

The BY, WO, DW, and POI operators are very useful with the J command

because they allow access to bytes, words, or dwords of memory in

conditional expressions, as follows:

   BY   1-byte value from the address

   WO   2-byte value from the address

   DW   4-byte value from the address

   POI  4-byte 16:16 address from the address

DW can be used to get a 32-bit flat address in an expression--for

example %(DW ESI).

Always put a zero in front of a hexadecimal number that begins with a

nonnumeric character. Doing so will prevent the debugger from treating

the number as a symbol and searching all the loaded symbol files. For

example, using 0f000 is faster than f000.

In Windows version 3.0, the backslash (\) prefix in front of registers

skips the symbol lookup and speeds up the expression evaluation; that

is, \DS:\SI is faster than DS:SI if many symbols have been defined. In

Windows version 3.1, even though the \ prefix is allowed, the \ is not

required to speed up register evaluation because registers are

evaluated first.

Default Command (Z)

-------------------

Syntax:

   ZD                  Run the default command

   ZL                  List the default command

   ZS "<command list>" Set the default command

The debugger's initial default command string is R (display

registers).

The debugger runs the default command string when:

 - It reaches a G (go) breakpoint

 - It reaches a software breakpoint set by BP (set breakpoint) or by

   BR (set debug register breakpoint), and the breakpoint does not

   have a corresponding breakpoint command string

 - It runs a P (program trace) or a T (trace) command

 - The user enters ZD at the debugger prompt

The ZS command changes the default command. If any errors occur (for

example, if the command line is too long), the default command returns

to the R command. The default command can be any sequence of debugger

commands each separated by a semicolon (;). In the default command, J

commands can be useful.

Examples

--------

 - Display 8 bytes pointed to by DS:SI, display the registers, and

   stop when DoSomething is executed:

      bp DoSomething "db ds:si l8;r"

 - Display 16 bytes pointed to by DS:ESI (the default segment register

   is DS) and continue execution every time DoSomething is executed:

      bp DoSomething "db esi l10;g"

 - Display the window handle, message type, word parameter, and long

   parameter of a Windows message procedure. Specifying sp+4 skips the

   far return address:

      bp MyWinProc "dw ss:sp+4 l6;g"

 - Display all the messages going to MyWndProc except for WM_TIMER

   messages:

      bp MyWinProc "j wo(ss:sp+6) == 113 'g';dw ss:sp+4 l6;g"

 - Display and stop each time MyWinProc receives a WM_PAINT message:

      bp MyWinProc "j wo(ss:sp+6) == 0f 'dw ss:sp+4 l6';g"

 - Break when the AX register equals zero:

      bp 167:1454 "j ax == 0;g"

 - If the byte pointed to by DS:SI+3 equals 40h when this breakpoint

   is hit, display the register and continue; otherwise, print the

   descriptor table entry in DS:

      bp 167:1452 "j by (ds:si+3) == 40 'r;g';dg ds"

 - Break when the BP address is reached in real mode:

      bp 156:1455 "j (msw and 1) == 1 'g'"

 - Because WDEB386 uses C language conventions for Boolean

   expressions, a shortcut that achieves the same result as above is:

      bp 156:1455 "j (msw and 1) 'g'"

 - Default command needed to continue execution each time the

   application or test program encounters an Interrupt 3:

      zs "j (by cs:ip) == 0cc 'g'"

 - Trace until the word at 40:1234h is equal to 0EEDh (a primitive

   watchpoint). This operation must be started with a T, a P, or a ZD

   command so that the default command can be executed. If this

   operation is started by the G command, the default command will not

   execute unless execution is stopped on a go breakpoint or on a

   sticky breakpoint with no breakpoint command.

      zs "j (wo 40:1234) == 0eed 'r';t"

      zd

 - Perform a trace that displays each instruction until control is

   returned to code segment or selector 2CFh. Notice that PN displays

   only the disassembly line and not the register set, saving line

   space on the debugger's terminal screen.

      zs "u cs:ip l1; j cs == 2cf 'r';pn"

      zd

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsWdeb


PRB: "Export Not Defined" Linker Message

Article ID: Q74699

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

The linker reports an "export not defined" error even though all the

functions listed in the EXPORTS section of the definitions (DEF) file are

defined.

CAUSE

=====

One of the exported functions uses the C calling convention (cdecl).

RESOLUTION

==========

In the C calling convention, the case of function names is preserved, and

the name of each function is preceded by an underscore. This convention

must also be used in the DEF file. For example, the function declaration

   int FAR Function()

is exported as:

   _Function

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: TlsMisc


Implicit Casting by C Compiler Can Cause Problems

Article ID: Q74739

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

When a function call is made in ANSI C, the compiler implicitly casts

the arguments passed to the function to the types specified in the

function's prototype. Implicit casting to promote signed integers or

characters (int, char) to longer unsigned types (DWORD, WORD) can

cause unexpected behavior. The difficulties occur because the signed

shorter value is promoted by extending its sign bit to the high-order

bits of the unsigned longer type.

An application can avert the problems caused by sign extension by

explicitly casting function arguments to unsigned short types.

MORE INFORMATION

================

In accordance with the ANSI standard, if the shorter value has the

sign bit set, the compiler first converts the value to a signed longer

value by extending the sign. The compiler extends the sign by filling

the high-order bits with 1s. It then converts the signed longer value

to unsigned by adding to it the number that is one larger than the

largest unsigned value of that type. This does not change the bit

pattern in a 2s complement implementation. For more information, see

Section 3.2.1.2 of the ANSI C Standard.

To see how this can cause unexpected behavior, consider an application

in the Microsoft Windows graphical environment that calls the

GlobalAlloc function. The second parameter of the function, dwBytes,

is an unsigned long quantity. However, in this application, this

parameter contains an signed integer expression that evaluates to a

number greater than the largest positive signed integer value

(32,767):

   HANDLE FAR PASCAL GlobalAlloc(WORD, DWORD);  // function prototype

   int a, b; // int = short (16-bit) signed integer

   a = 9500;

   b = 4;

   GlobalAlloc(GMEM_MOVEABLE, a*b);

The result of a*b is 38,000 (1001010001110000), and the sign bit of

the int is set. To implement the implicit cast to an unsigned long

value (DWORD), the value is first converted to a signed long value:

   11111111111111111001010001110000

The value that is one greater than the largest unsigned long value is

then added, as follows:

      11111111111111111001010001110000

   + 100000000000000000000000000000000

   -----------------------------------

      11111111111111111100101000111000 (4,294,939,760 decimal)

GlobalAlloc attempts to allocate 4,294,939,760 bytes of memory rather

than 38,000, and it fails. The GlobalAlloc call in the application

should be as follows:

   GlobalAlloc(GMEM_MOVEABLE, (WORD)a*(WORD)b);

Problems caused by implicit casting and sign extension are also

encountered frequently when an application passes characters to the

AnsiUpper and AnsiLower functions. The prototypes for these functions

are as follows:

   LPSTR FAR PASCAL AnsiUpper(LPSTR);

   LPSTR FAR PASCAL AnsiLower(LPSTR);

To pass a signed character to AnsiUpper,

   AnsiUpper((DWORD)(BYTE)c) is correct,

   AnsiUpper((DWORD)c) is incorrect.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsMisc


Using Near and Far Pointers with C Run-Time Functions

Article ID: Q74788

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In an application designed for the Microsoft Windows graphical environment,

many C run-time functions do not work with memory allocated by the

GlobalAlloc() function when the application is developed in the small or

medium memory model.

MS-DOS (non-Windows) applications written in the small or medium memory

model assume the presence of only one data segment (DS). Therefore, the C

Run-time functions assume that DS will not change.

However, an application can store data in a block of memory allocated with

the GlobalAlloc() function and locked with the GlobalLock() function. The

segment returned from GlobalLock() will be different from the application's

data segment. Specifying the alternate data segment in a C run-time

function that assumes a near pointer results in the following C compiler

warning:

   WARNING: Segment Lost in Conversion

For example, the following code passes far pointers to a Run-time function

incorrectly:

   hMem = GlobalAlloc (...);

   lpMem = GlobalLock (hMem);

   strcpy (szBuffer, lpMem);

   GlobalUnlock (hMem);

This section of incorrect code produces one of two results.

1. If the offset of lpMem extends past the end of application's data

   segment (DS), the application experiences an unrecoverable

   application error (UAE).

2. The function copies information from some random portion of the

   application's DS into the buffer.

If the following line of code is used, the function overwrites data in the

application's data segment, which causes the application to crash or run

incorrectly:

   strcpy (lpMem, szBuffer);

Four ways to work around this situation are:

1. For the most common C run-time functions, Windows provides

   equivalent functions that use far pointers. These functions

   include:

      lstrcat()

      lstrcmp()

      lstrcmpi()

      lstrcpy()

      lstrlen()

2. Use the far pointer versions of these functions (_fstrcat(),

   _fstrcmp(), and so on) provided by the Microsoft C Optimizing

   Compiler versions 6.0 and later.

3. For the less common C Run-time functions, write a far-pointer

   version as part of the application code. Most of the Microsoft C

   Run-time library source code is available from Microsoft.

4. Use the large memory model.

   NOTE: Using the large memory model in Windows 3.0 had many disadvantages

   and doing so was not encouraged. These problems were corrected in

   Windows 3.1 and Microsoft C/C++ compiler. Hence, using the large memory

   model is not a problem.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsMisc


Rich Text Format Subset Supported by Windows Help

Article ID: Q75010

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Windows Help Compiler version 3.0 does not support all of the

formatting options that word processors, such as Microsoft Word for

Windows or Microsoft Word for the Macintosh, are capable of creating.

This document briefly lists many of these unsupported formats.

The complete specification of the Rich-Text Format (RTF) is included

in the Microsoft Word for Windows Technical Reference (Microsoft

Press).

MORE INFORMATION

================

Most of the time, unsupported format information is ignored by the

Help Compiler without any warning messages.

The following items are not supported by Windows Help 3.0 in any form:

   Absolute-positioned objects

   Annotations

   Bookmarks

   Document formatting properties

   Document information

   Headers and footers

   Index entries

   Style sheets

   Table of contents entries

   Tables

NOTE: In Windows Help version 3.1, Word for Windows tables are supported.

The following items are used for specified purposes in the Help

Compiler:

Footnotes

---------

Note that the footnotes are "overloaded" and used for build tags,

context strings, browse sequences, keywords, alternate keywords, and

topic titles by the Help Compiler.

The group containing footnote text begins with the control word

"\footnote". Footnotes are anchored to the character that immediately

precedes the footnote group. If automatic footnoting is defined, the

group can be preceded by a footnote reference character, identified by

the control word "\chftn". The following is an example of a group

containing footnotes:

NOTE: The "\chftn" control word is ignored in version 3.1 of the Help

compiler.

...

\ftnb\ftnrestart \sectd \linemod0\linex0\endhere \pard\plain \ri1170

\fs20 {\up6 Mead's landmark study has been amply annotated.\chftn

{footnote \pard\plain \s246 \fs20 {\up6\chftn }See Sahlins, Bateson,

and Geertz for a complete bibliography.}

It was her work in America during the Second World War, however, that

forms the basis for this paper. As others have noted, \chftn {footnote

\pard\plain \s246 \fs20 {\up6\chftn A complete bibliography will be

found at the end of this chapter.}

this period was a turning point for Margaret Mead.}

\par

...

Character Formatting Properties

-------------------------------

The last group of RTF control words controls character formatting

properties. A control word preceding plain text turns on the specified

attribute. Some control words (indicated by an asterisk following the

description) can be turned off by the control word followed by 0

(zero).

   Control Word   Meaning

   ------------   -------

   \plain         Resets application's default character formatting

                  properties

   \b             Bold*

   \i             Italic*

   \strike        Strikethrough. Overloaded. Used to indicate a jump term

                  (hot spot).

   \scaps         Small capitals*

   \v             Hidden text. Overloaded. Used to indicate the context

                  string of the jump destination.

   \f#            Font number. (Replace # with the appropriate number.)

   \fs#           Font size in half-points (default is 24) (Replace #

                  with the appropriate number).

   \ul            Continuous underline*

   \uldb          Double underline Overloaded. Used to indicate a jump

                  term (hot spot).

In order to read negative \expnd values created by Word for the

Macintosh, Windows Help uses only the low-order 6 bits of the value

read. Word for the Macintosh does not emit negative values for \expnd.

Instead, it treats values from 57 to 63 as -7 to -1, respectively (the

low-order 6 bits of 57 to 63 are the same as -7 to -1).

Special Characters

------------------

Special RTF characters are listed below. If a character is not

recognized by the RTF reader, it is ignored and the text following it

is considered plain text. The RTF specification is flexible enough to

allow new characters to be added for interchange with other software.

   Control Word   Meaning

   ------------   -------

   \'hh           A hexadecimal value, based on the specified character

                  set (may be used to identify 8-bit values).

An ASCII 9 will be accepted as a tab character. The code \<ASCII10>

(line feed) or \<ASCII13> (carriage return) is treated as the control

word \par. The backslashes must be included or RTF will ignore the

control word. It is also desirable to insert a carriage-return/line-

feed pair (without backslashes) at least every 255 characters for

better text transmission over communication lines.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsHlp


Tips on Installing WDEB386

Article ID: Q75252

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Windows 80386 debugger, WDEB386, provided with the

Microsoft Windows Software Development Kit (SDK) is automatically made

available by the installation process; however, additional procedures

may be needed to take full advantage of the features it provides. This

article describes the procedures necessary to fully configure this

protected-mode debugger.

MORE INFORMATION

================

Hardware

--------

A terminal connected to a COM port is required to use WDEB386. Unlike

Microsoft CodeView for Windows (CVW), WDEB386 does not support running

the debugger on a secondary monitor. Optionally, attach a second

computer to a COM port on the primary computer. Running the Windows

Terminal application on the second machine allows you to save and

print portions of debug traces and memory dumps.

Use the /C:n option (where n is 1 or 2) to specify which COM port to

use with WDEB386. WDEB386 sends all output to the specified COM port.

However, if the debugging version of WIN386.EXE (explained below) is

run without running WDEB386, output is directed by default to COM1.

Related Files

-------------

Because of the similarity of the names of a number of files, there is

some confusion as to what the debugger is and how to install and use

it. The following list describes some files that have similar names,

but completely different functions.

WDEB386.EXE  - This file is the actual WDEB386 debugger. The debugger

               is described in more detail in Chapter 5 of the

               "Programming Tools" manual distributed with the Windows

               SDK version 3.1 and in Chapter 9 of the "Tools" manual

               distributed with the Windows SDK version 3.0.

WIN386.EXE   - This executable file comprises the core of the Windows

               enhanced-mode operating system layer. It includes the

               VMM (virtual machine manager), and various standard

               VxDs (virtual devices).

WINDEBUG.386 - This VxD may be installed in Windows running in

               enhanced mode (it is not included in WIN386.EXE). It

               provides a number of low-level services for debuggers,

               the most well-known being the ability to use the key

               combination CTRL+ALT+SYS RQ as a break request. This

               VxD is not necessary for WDEB386 to function properly.

By default, the WDEB386.EXE file is installed in the C:\WINDEV

directory, which makes it available in the MS-DOS PATH environment

variable. The WINDEBUG.386 file is also installed during the SDK

installation process. The file itself is copied to the Windows system

directory (by default, C:\WINDEV\SYSTEM), and the line

"DEVICE=WINDEBUG.386" is added to the [386enh] section in the

SYSTEM.INI file. Therefore, these modules should require no special

attention regarding their installation.

WIN386.EXE

----------

Special care may be required concerning WIN386.EXE. The retail version

of this file is part of Windows, and Windows does not run in enhanced

mode without it. To take advantage of some of the more advanced and

extremely useful features of WDEB386, however, the debugging version

of WIN386.EXE must first be installed. This step is optional, but

without it, a significant number of WDEB386 commands are not

available.

Most programmers are aware of the procedure to install "the debugging

version of Windows." This procedure is not sufficient to install the

debugging version of WIN386.EXE. The difference is that the debugging

version of Windows consists of the debugging versions of the kernel,

user, and GDI modules, along with their corresponding symbol files.

These files are all available as part of the SDK. In contrast, the

debugging version of WIN386.EXE is available only as part of the

Microsoft Windows Device Driver Kit (DDK) in the 386\TOOLS\DEBUG

directory. (Under Windows 3.0, the file is in the DDK VXD\TOOLS\DEBUG

directory.)

Therefore, even after installing the debugging version of Windows, an

additional action is required to install the debugging version of

WIN386.EXE. Installing WIN386.EXE is easy. Copy the retail version of

WIN386.EXE to a different filename and copy the debugging version from

the DDK disks into the Windows system directory. The retail version

has a file size of around 500K bytes, whereas the debugging version is

significantly larger.

NOTE: The SYM file for the debugging version of WIN386.EXE is not

available. There is a WIN386.SYM file supplied on the DDK in the same

directory as the debugging version of WIN386.EXE, but this file

contains the symbols for the retail version, and does not contain

symbol information that matches the accompanying EXE file. Attempting

to use this SYM file is worse than not using one at all because it

assigns labels to addresses incorrectly.

The Grabber

-----------

Once the debugging version of WIN386.EXE is installed, it may also be

necessary to install the debugging version of the "grabber" file. To

determine if the debugging grabber is required, start the debugging

Windows system in enhanced mode and attempt to start an MS-DOS

session. If the attempt fails with the message "Incorrect System

Version," then it is necessary to build and install the debugging

version of the 386 grabber. This should be in the \386\GRABBER

directory in the DDK (under Windows 3.0, this file is in the

\VXD\GRABBER directory). Set the DEBUG flag in the makefile, build the

grabber with the MAKE utility, and copy the grabber to the Windows

system directory. You can change the name of the file, however, the

"386grabber=" line in the SYSTEM.INI file must reflect the correct

name. If it is possible to start an MS-DOS session on the Windows

debugging system while running in enhanced mode, then this step has

been completed successfully.

Starting the Debugger

---------------------

During the process of testing the grabber, you should see a number of

messages written to the COM1 terminal by Windows. These messages

indicate that the debugging version of WIN386.EXE has been correctly

installed, and that the system is ready for the debugger. At this

point, refer to Chapter 5 of the "Programming Tools" manual (or

Chapter 9 of the "Tools" manual) for instructions on starting and

using the debugger. For some tips on using the WDEB386 debugger, query

on the words:

   wdeb386

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsWdeb


Creating a Nonscrollable Region in Windows Help 3.1

Article ID: Q76493

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Version 3.1 of the Windows Help engine supports the ability to author

topics to contain a nonscrolling region of text immediately below the

button bar. Text and graphics remain in this fixed location even as

the user scrolls other text in the topic. This nonscrolling region

appears the same as other text, except a thin black line divides the

nonscrolling region from the rest of the text in the topic. This

region can contain any of the formats applicable to a help file (hot

spots, bitmaps, and so forth).

MORE INFORMATION

================

To create a nonscrolling region, you must create the \pard\keepn

rich-text format (RTF) token. To accomplish this using Microsoft Word

for Windows version 2.0, perform the following four steps:

1. Select the text to place in the nonscrolling region.

2. From the Format menu, choose Paragraph.

3. In the Paragraph dialog box, select the Keep With Next check box

   under Pagination.

4. Choose the OK button or press the ENTER key.

The background color attribute of the nonscrollable region can be

changed in the [WINDOWS] section of the help project (.HPJ) file. The

characteristics of any window in the help file may be specified in the

[WINDOWS] section. Use the following syntax to perform this step:

type-name="caption", (horizontal_position, vertical_position, width,

     height), sizing, (client-RGB), (nonscrolling-RGB)

To change the color of the nonscrolling region, modify the final RGB

triple. For example, the following specification will change the

background color of the nonscrolling region to red:

   main="",,0,,(255,0,0)

Additional reference words: 3.10 3.1 non-scrolling non-scrollable

KBCategory: kbtool

KBSubcategory: TlsHlp


PRB: Resource Compiler Cannot Find Include Files

Article ID: Q76688

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When the Resource Compiler (RC) is used to compile a resource script, it

cannot locate include files.

CAUSE

=====

The environment variable INCLUDE contains a path that ends in

a backslash (example, set INCLUDE=C:\).

RESOLUTION

==========

Change the declaration of the environment variable to remove the

trailing backslash.

This problem is often caused when the SUBST command is used to

specify a logical drive for a path.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsRc


PRB: Value of hPrevInstance Incorrect

Article ID: Q76940

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

NOTE: The information below does not apply to Visual C++.

SYMPTOMS

========

The value of hPrevInstance is not equal to NULL, even though there are no

other instances of the program running.

CAUSE

=====

The C Run-time library used by the linker does not match the memory model

specified in the C compiler.

RESOLUTION

==========

Change the run-time library used by the linker to reflect the appropriate

memory model used in the C compiler.

MORE INFORMATION

================

The following table associates the memory model with the C Run-time

library names:

   Memory Model  Compiler Switch  Run-Time Library

   ------------  ---------------  ----------------

   Small              -AS         SLIBCEW.LIB

   Medium             -AM         MLIBCEW.LIB

   Large              -AL         LLIBCEW.LIB

   Compact            -AC         CLIBCEW.LIB

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMisc


PRB: Problems with Dr. Watson or with the Packager

Article ID: Q77066

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Neither Dr. Watson nor the Packager runs correctly.

CAUSE

=====

An old version of the TOOLHELP.DLL file is in the main Windows directory

(by default, C:\WINDOWS).

RESOLUTION

==========

Verify that Windows has installed TOOLHELP.DLL in the Windows system

directory (by default, C:\WINDOWS\SYSTEM). Delete the old TOOLHELP.DLL from

the Windows directory.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: TlsDrWatson


Correctly Configuring PWB for Windows Development

Article ID: Q77071

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article describes how to set up Programmers WorkBench (PWB) so

that it will properly create a Windows executable. This method cannot

be used to create a Windows program with multiple named code segments.

Creating applications with multiple named code segments is discussed

in the PWBINFO.WRI file distributed with the Windows Software

Development Kit (SDK). The SDK installation procedure copies

PWBINFO.WRI into the Windows development directory (by default,

C:\WINDEV).

MORE INFORMATION

================

To create a Windows program, several modifications must be made to the

PWB build options. The first step is to set the initial build options

to Windows EXE. To change the initial build options, perform the

following three steps:

1. Choose Build Options from the Options menu.

2. Choose Set Initial Build Options in the Build Options dialog box.

3. Choose Windows EXE from the list of initial build options.

Once the initial build options have been set, verify that the packed

executable file option is disabled for both the debug and release

options. The following eight steps describe how to disable the packed

executable file option:

1. Choose Link Options from the Options menu.

2. Choose Set Release Options in the Link Options dialog box.

3. Disable the Pack EXE File option in the LINK Release Options dialog

   box.

4. Click OK.

5. Choose Set Debug Options in the Link Options dialog box.

6. Disable the Pack EXE File option in the LINK Debug Options dialog

   box.

7. Click OK.

8. Click OK.

Next, the correct math library must be selected. Proceed with the

following eight steps to enable the correct math emulation for both

the debug and release options:

1. Choose the C Compiler Options command from the Options menu.

2. Choose Set Debug Options in the C Compiler Options dialog box.

3. Enable the Emulation Calls option in the C Compiler Debug Options

   dialog box.

4. Click OK.

5. Choose Set Release Options in the C Compiler Options dialog box.

6. Enable the Emulation Calls option in the C Compiler Release Options

   dialog box.

7. Click OK.

8. Click OK.

Next, enable the correct C compiler library. The following two steps

set the library to the Windows library:

1. Choose C Compiler Options from the Options menu.

2. Select the Windows C Libraries in the C Compiler Options dialog

   box.

At this point, save the build options for PWB to the disk. The

following two steps accomplish this:

1. Choose the Build Options command from the Options menu.

2. Choose Save Current Build Options in the Build Options dialog box.

Once the current build options have been saved, it is necessary to set

the initial build options each time PWB is started. This ensures that

the PWB session will use the appropriate build settings instead of the

default settings. When beginning subsequent PWB sessions, follow these

three steps:

1. Choose the Build Options command from the Options menu.

2. Choose Set Initial Build Options in the Build Options dialog box.

3. Select the name of the set of build options that were previously

   saved. This name appears near the bottom of the Set Initial Build

   Options list.

To create a Windows program, it is necessary to create a program list.

The four steps required to do this are as follows:

1. Choose the Set Program List command from the Make menu.

2. Replace the asterisk in the File Name field of the Set Program List

   dialog box with the name of the program list file to create.

3. Select Yes when PWB displays the "File Does Not Exist" message box.

4. Build the program list by selecting the files in the File List

   required by the program, selecting Add/Delete for each file. Be

   sure to include all C, DEF, and RC files.

Once the program list has been created, the options on the Make menu

are available to compile or recompile the program. For more

information on the Make menu, please consult the PWB documentation.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsMisc


PRB: Causes of Help Compiler "Table Too Complex" Warning

Article ID: Q77935

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

During the processing of a Windows Help file, the Help Compiler

returns the warning "Table Too Complex."

CAUSE

=====

The RTF (rich text format) source file contains a table that has

been formatted using with one or more attributes that the Help

Compiler does not recognize.

RESOLUTION

==========

Modify the formatting of the table to remove any unsupported

formats.

MORE INFORMATION

================

Only simple tables are supported by the Windows 3.1 Help Compiler. The

following formats generate the "Table Too Complex" warning:

   - Borders

   - Rules

   - Shading

These three formats are ignored by the Help Compiler. When the table

is displayed in Windows Help, these formats are absent.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


Swap Tool Not Included with Windows SDK 3.1

Article ID: Q77936

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The swap analysis tool provided with the version 3.0 of the Windows

Software Development Kit (SDK) is not included with version 3.1 of the

Windows SDK. The Windows 3.0 swap program was designed to run only in

Windows real mode, which has been removed from Windows 3.1.

MORE INFORMATION

================

There are several tools available to assist with segment optimization.

Use the Microsoft Source Profiler to identify functions that are used

or "hit" frequently. These functions can be grouped into the same

segment. Alternatively, use a third-party source optimization tool

such as The Segmentor from MicroQuill. Finally, one can write a

segment optimization tool using the resources of the ToolHelp library

provided with version 3.1 of the Windows SDK.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsPrf


Debugging GP Faults with WDEB386

Article ID: Q77987

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Under certain circumstances, trying to trap GP (general protection)

faults with WDEB386 may produce unexpected results.

In general, if the processor generates a GP fault while a Windows-based

application is running, the GP-fault handler will automatically

provide the mechanism to stop at the offending instruction in WDEB386.

However, unexpected results (breaking at unusual locations, infinite

loops, debugger crashes) may occur under WDEB386 if one of the

following conditions is true:

- The GP fault occurs somewhere other than in a Windows-based application

  or dynamic-link library (DLL).

- The WIN.INI file [kernel] section switch DisableGPTrapping is set to

  1.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsWdeb


PRB: Help Compiler Warning "Using Old Key Phrase Table" Cause

Article ID: Q78119

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When building a help file, the Help Compiler issues the warning "Using Old

Key Phrase Table."

CAUSE

=====

A key-phrase file (a .PH file) exists at compile time.

RESOLUTION

==========

Delete the key-phrase file.

MORE INFORMATION

================

When the Help Compiler builds a help file and the compression option is

specified, it creates a phrase table file with the .PH extension as part of

the compilation process. Because creating the phrase table is a time-

consuming process, the Help Compiler will issue the "Using Existing Key

Phrase Table" warning and use an existing .PH file (if a .PH file is

available) instead of creating a new one. This technique minimizes the

compilation time for modifications to an existing help file. However, to

obtain maximum compression, a new phrase table must be created.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


Help Does Not Support Side-by-Side Paragraphs

Article ID: Q78242

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The Windows Help Compiler version 3.1 no longer supports the "side-by-

side" paragraph format provided by Microsoft Word for MS-DOS and Microsoft

Word for the Macintosh. This format was used in files compiled by version

3.0 of the Windows Help Compiler to create multiple columns of information.

To create multiple columns in a file compiled with version 3.1 of the

Help Compiler, use the Table feature provided by Microsoft Word for

Windows.

Help files that are authored using side-by-side paragraphs and compiled

using version 3.0 of the Help Compiler will continue to be supported using

version 3.1 of Windows Help (the help file viewer).

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsHlp


PRB: Combining Multiple Compiled Resource Files Fails

Article ID: Q80281

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

An application is unable to load some of its resources, while other

resources load properly.

CAUSE

=====

Several small compiled resource (RES) files have been combined

using the MS-DOS command "COPY /b".

RESOLUTION

==========

Use the #include directive to combine the files at the source

level.

MORE INFORMATION

================

The Resource Compiler that was shipped with the Microsoft Windows

Software Development Kit (SDK) versions 2.x ca not handle large

resource files because of inherent memory limitations. To work around

these limitations, it is recommended that programmers compile the

resources into small RES files, and combine these files using the

MS-DOS COPY /b command.

The Resource Compiler shipped with version 3.x of the Windows SDK has

been enhanced to handle resource files much larger than its Windows

2.x counterpart. The format of the compiled resource files in Windows

3.x does not support concatenation of RES files.

If an application has a large number of resources, even the version

3.x Resource Compiler can run out of memory. If this occurs, modify

the design of the application to use a resource-only dynamic-link

library (DLL). The following three steps outline the required process

to perform this type of functionality:

1. Use the Resource Compiler to create a resource-only DLL that

   contains some of the application's resources. See the note below

   regarding resource-only DLLs under Windows 3.x.

2. In the application, load the resource library using the

   LoadLibrary function.

3. Use the LoadBitmap, LoadMenu, and so forth, functions to load

   resources from the DLL as required.

Under Windows 3.x, resource-only DLLs require a Windows exit procedure

(WEP). The WEP must be exported in the DEF file and the export must

have the RESIDENTNAME attribute. Place the code for the WEP into a

FIXED code segment. The source code for a WEP follows:

   int far pascal WEP(int NotUsed)

      {

      return 1;

      }

The "far" and "pascal" declarators are in lowercase to avoid having to

include the WINDOWS.H header file.

Additional reference words: 3.00 3.10 dialog icon menu bitmap cursor font

rcdata stringtable

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsRc


Windows 3.1 Application Compatibility (part 1 of 7)

Article ID: Q80896

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Application Compatibility Document for Windows 3.1

--------------------------------------------------

To make Windows version 3.1 better and more robust than Windows

version 3.0, Microsoft enhanced and improved many Windows features.

Although every effort was made to ensure compatibility with

applications developed for Windows version 3.0, some enhancements may

affect the operation of these applications -- especially if an

application uses features in an undocumented fashion or relies on

invalid assumptions about the behavior of Windows.

Microsoft is eager to help you resolve any compatibility problems you

may encounter. This document identifies the enhancements that may

affect existing Windows version 3.0 applications and explains how you

can determine whether your application will run successfully under

Windows version 3.1.

Please read each section carefully and use the "Windows 3.1

Compatibility Test" (available separately) as a checklist to ensure

that you have carried out the recommended tests. As you complete each

test, mark whether your application passed or failed the test. If your

application failed a test, please supply comments that will help

Microsoft determine the cause of the compatibility problem. If you

choose not to carry out a test, please indicate why in the comments

section.

When you have completed the Compatibility Test, return it to:

   Windows Compatibility Test

   Microsoft Corporation

   One Microsoft Way

   Building 4

   Redmond, WA 98052-6399

Due to the amount of information in this document, it has been broken

into seven pieces. To find all seven pieces of this document and the

Windows 3.1 Compatibility Test checklist, query this knowledge base on

the words:

   prod(winsdk) and 31compattest

                   Application Installation Programs

                   =================================

Enhancements to the Program Manager's group file format and extensions

to the PROGMAN.INI file may affect your application's installation

program.

Potential Problem

-----------------

Your installation program may not correctly add your application's

icon to Program Manager or may not correctly save your application's

PROGMAN.INI settings.

Tests

-----

Run your installation program in each of the following applicable

environments:

 - MS-DOS

 - MS-DOS command prompt under Windows version 3.1

 - Windows using the Run command in the Program Manager's File menu

                             Windows Setup

                             =============

Windows version 3.1 Setup is easier to use, faster, more robust, and

capable of detecting more hardware and network configurations than was

the Windows version 3.0 Setup. Special attention was given to the need

to upgrade from Windows version 3.0 while maintaining existing group

files and WIN.INI settings.

Potential Problem

-----------------

Setup may fail to correctly preserve your application's program group

files and WIN.INI settings.

Test

----

Use Setup to install Windows version 3.1 on a computer on which both

Windows version 3.0 and your application are already installed. After

installation, be sure that your application's WIN.INI settings are

correct and that your application runs properly.

                         Shell Application

                         =================

This section applies only to applications that replace the standard

Windows shell application, Program Manager. The shell application (as

specified by the "shell" setting in the SYSTEM.INI file) is no longer

guaranteed to be the first process.

Potential Problem

-----------------

An application that assumes it is the shell only when it is the first

process will not exit Windows correctly when terminated.

Test

----

Make your application the shell by specifying your application's

executable filename with the "shell" setting in the SYSTEM.INI file.

Exit Windows and be sure Windows terminates correctly.

Solution

--------

Your application must determine whether it is the shell by doing the

following:

1. Check the number of processes running when it starts.

2. If more than one process is running, check the shell setting in the

   SYSTEM.INI file.

                      Windows Shell Applications

                      ==========================

Enhancements to the Program Manager, File Manager, Print Manager, and

Control Panel may affect your application.

DRAG AND DROP

-------------

Drag and drop was reimplemented, and Windows now exports the drag-drop

functions and message (WM_DROPFILES).

Potential Problem

-----------------

An application that reverse-engineered the Windows version 3.0 drag-

drop protocol may encounter difficulties.

Tests

-----

1. Drag a file from File Manager to your application. Be sure your

   application opens the proper file.

2. Drag a file associated with your application to Print Manager. Be

   sure your application opens and prints the proper file.

SYSTEM COLORS

-------------

Windows now provides more system colors and user preferences. Users

can select separate colors for active and inactive title bar text,

button face, button shadow, button text, button highlight, disabled

text, highlight, and highlighted text. Different wallpapers and color

schemes were added, and the default color scheme is changed.

Potential Problem

-----------------

An application may not use all colors correctly.

Test

----

Display your application's windows, dialog boxes, and controls, and

check the colors of the active and inactive title bar text, button

face, button shadow, button text, button highlight, disabled text,

highlight, and highlighted text colors. Use the Control Panel to set

each of the following system color schemes:

 - System colors set to default.

 - System colors set to a nondefault color scheme, such as Arizona.

 - System colors set to a random scheme in which you set colors

   individually. (Don't use the predefined color schemes.)

CARDFILE AND WRITE FILES

------------------------

The Cardfile file format is changed, and both Cardfile and Write

documents can now contain embedded OLE objects.

Potential Problem

-----------------

Any application that makes assumptions about Cardfile and Write file

formats may not be able to read or write to these files correctly.

Tests

-----

1. Use your application to create Cardfile or Write files. Use Windows

   version 3.1 Cardfile and Write to open and view the files.

2. Use Windows version 3.1 Cardfile and Write to create files

   containing OLE objects. Be sure your application can open and read

   the files.

OTHER CONSIDERATIONS

--------------------

 - Path searching is enhanced. When trying to load DLLs, Windows

   searches directories in the following order: current directory,

   Windows directory, System directory, application directory, path.

   The application directory is new for Windows version 3.1.

 - Title fonts for Program Manager and desktop icons are changed, and

   icon titles can now wrap.

 - More than one printer can now be installed on a port.

 - Control Panel's font installation is enhanced.

 - Program Manager automatically reconnects network drives and devices

   when Windows is restarted.

 - File Manager is entirely new for Windows version 3.1. File Manager

   includes an interface that lets applications add menu items to File

   Manager menu by using a File Manager extension library.

 - Control Panel now provides an interface for adding new Control

   Panel applications and icons.

 - The Startup group contains applications that load whenever Windows

   is started. For backward compatibility, Windows continues to

   support the "load" line in the WIN.INI file.

 - The [intl] section in the WIN.INI file is enhanced. More date

   formats and currency symbols are available.

 - Desktop spacing can now be changed by a new setting in the WIN.INI

   file and by the SystemParametersInfo function.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsCompat


Windows 3.1 Application Compatibility (part 2 of 7)

Article ID: Q80897

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Application Compatibility Document for Windows 3.1

--------------------------------------------------

Due to the amount of information in this document, it has been broken

into seven pieces. To find all seven pieces of this document and the

Windows 3.1 Compatibility Test checklist, query this knowledge base on

the words:

   prod(winsdk) and 31compattest

                         Multimedia and Sound

                         ====================

Windows version 3.1 includes multimedia and sound drivers. Most of

these enhancements should affect only applications that use the sound

functions. Applications that use unusual drivers, such as fax machine

applications, should also test to be sure the sound drivers don't

interfere.

MS-DOS SOUND APPLICATIONS

-------------------------

Potential Problem

-----------------

Some MS-DOS-based applications that use audio cards, such as SoundBlaster,

may not run correctly in virtual machines or may run incorrectly after

Windows terminates.

Test

----

Carry out each of the following steps. Be sure your application runs

correctly as you complete each step:

1. Run the MS-DOS-based application in a virtual machine.

2. Exit Windows and run your application under MS-DOS.

WINDOWS SOUND APPLICATIONS

--------------------------

Potential Problem

-----------------

Although Windows sound functions are 100 percent backward compatible,

some Windows-based applications may not function properly with the new

functions.

Test

----

Run your application and try all the sound capabilities.

UNUSUAL DRIVERS

---------------

Potential Problem

-----------------

Applications requiring unusual drivers, such as WinFax, may not be

compatible with Multimedia extensions.

Test

----

Run your application and try the functions of your application that

the driver supplies.

                          Window Management

                          =================

The window management (User module) enhancements may affect Windows

3.0 applications. To test this, perform as many operations as possible

that will move, size, scroll, and repaint your application windows.

The following sections list a few basic methods to try, but also try

as many other methods as possible.

In some cases, Windows version 3.1 will ensure compatibility with

existing Windows version 3.0 applications by supporting both the

Windows versions 3.0 and 3.1 implementations. If an application's

Windows version as set by Resource Compiler (RC) is 3.0, Windows

version 3.1 carries out the Windows 3.0 implementation; that is, the

Windows version 3.1 enhancement has no impact on an existing Windows

version 3.0 application. However, if a Windows version 3.0

application's Windows version is changed to 3.1 without corresponding

changes to the application code, the application may encounter

problems wherever Windows version 3.1 carries out the 3.1

implementation.

MOVING AND SIZING

-----------------

For Windows 3.0 applications, the SetWindowPos function assumes that

SWP_NOMOVE and SWP_NOSIZE are set if SWP_HIDEWINDOW or SWP_SHOWWINDOW

was set. Thus, hiding and showing a window and changing its size and

position are not possible in an atomic operation. Windows version 3.1

applications are not so limited.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may make unnecessary calls to SetWindowPos.

In a Windows version 3.0 application, if you call SetWindowPos with

SWP_SHOWWINDOW when the window is already visible, SetWindowPos always

causes the entire window to be redrawn. This also affects the

operation of ShowWindow. In a Windows version 3.1 application, a call

to SetWindowPos with SWP_SHOWWINDOW on a window that is already

visible will not redraw (unless other areas must be updated as a

result of a size, move, or z-order operation specified in addition to

SWP_SHOWWINDOW).

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it depends on redrawing on each call to

SetWindowPos with SWP_SHOWWINDOW set.

MoveWindow is shorthand for a call to SetWindowPos with the

SWP_NOZORDER and SWP_NOACTIVATE flags set. If the MoveWindow fRedraw

parameter is FALSE, then SWP_NOREDRAW is also set. In a Windows 3.0

application, when MoveWindow is called on a top-level window with

fRedraw set to FALSE, Windows calls SetWindowPos without setting the

SWP_NOREDRAW flag and then calls ValidateRect to prevent the client

area from repainting. However, WM_NCPAINT and WM_ERASEBKGND messages

will have been sent, even though fRedraw was FALSE. In a Windows

version 3.1 application, MoveWindow no longer makes this special case.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it depends on receiving WM_NCPAINT and

WM_ERASEBKGND messages after a call to MoveWindow.

In a Windows version 3.0 application, Windows always redraws a

window's frame completely when the window is moved or sized. In a

Windows version 3.1 application, Windows no longer redraws a window's

frame completely in all cases. For example, the following code

sequence will not redraw the window border:

   MoveWindow(hwnd, ..., FALSE);

       .

       .

       .

   InvalidateRect(hwnd, NULL, TRUE);

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may have an incomplete window frame if it depends on Windows

redrawing the frame completely after moving and sizing.

Tests

-----

1. Start your application in its default state. Maximize and minimize

   it; be sure it paints correctly after each operation.

2. Move your application as far right and left as you can in small

   increments, watching for repaint problems each time you stop

   moving.

3. Resize your application using the mouse to drag the border.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsCompat


Windows 3.1 Application Compatibility (part 3 of 7)

Article ID: Q80898

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Application Compatibility Document for Windows 3.1

--------------------------------------------------

Due to the amount of information in this document, it has been broken

into seven pieces. To find all seven pieces of this document and the

Windows 3.1 Compatibility Test checklist, query this knowledge base on

the words:

   prod(winsdk) and 31compattest

PAINTING

--------

In Windows version 3.1, Window management is substantially optimized

to avoid unnecessary redrawing and flashing. Applications that depend

in subtle ways on when (and if) WM_NCPAINT, WM_ERASEBKGND, and

WM_PAINT messages are sent may have incompatibilities. Windows version

3.0 frequently sent these messages redundantly to windows and

sometimes sent them to invisible windows. One of the most apparent

visual results of these optimizations is that a window's nonclient

area is not always repainted completely when a window is sized or

moved. Some attempt has been made to ensure compatibility, but some

differences still cannot be backward compatible and achieve the

significant performance and visual advantages.

In a Windows version 3.0 application, sending the WM_SETREDRAW message

with wParam set to FALSE to a window that had an update area does not

validate the window. The update area is still present after a

WM_SETREDRAW message with wParam set to TRUE. In a Windows version 3.1

application, WM_SETREDRAW with wParam set to FALSE validates the

window completely to ensure that the window does not receive any

WM_PAINT messages while it is invisible. This does not apply to edit

controls, list boxes, and combo boxes because their WM_SETREDRAW

messages are handled in a special-case manner.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it depends on retaining the update area

after a WM_SETREDRAW message.

In a Windows version 3.0 application, when InvalidateRect or

InvalidateRgn is called with NULL to invalidate the entire window, all

child windows are also completely invalidated -- regardless of whether

the child window is outside the parent's client area (that is,

invisible). This results in WM_PAINT messages being sent to windows

that don't require them. In a Windows version 3.1 application, only

windows that are actually visible within a parent's client area

receive update regions and therefore WM_PAINT messages.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it depends on its child windows

receiving WM_PAINT messages even when invisible.

In a Windows version 3.0 application, Windows sends a WM_SETVISIBLE

message immediately after sending the WM_SHOWWINDOW message. In a

Windows version 3.1 application, Windows does not send the

WM_SETVISIBLE message -- WM_SETVISIBLE is obsolete for Windows version

3.1.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it depends on receiving the

WM_SETVISIBLE message.

In a Windows version 3.0 application, if BeginPaint is called on a

window that has a class icon, the function returns a window DC. This

is different from the GetDC function that returns a client DC with no

visible region. In a Windows version 3.1 application, BeginPaint and

GetDC both return a client DC with no visible region.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it depends on receiving a window DC from

BeginPaint.

If a Windows version 3.0 application responds with FALSE to a

WM_ERASEBKGND message sent during any operation other than BeginPaint

(such as SetWindowPos), another WM_ERASEBKGND message is sent when the

application calls BeginPaint. If a Windows version 3.1 application

responds with FALSE, no second WM_ERASEBKGND message is sent, but

BeginPaint sets the fErase member of the PAINTSTRUCT structure to

TRUE.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it does not check the fErase member

after calling BeginPaint.

In Windows version 3.0, the various controls call the UpdateWindow

function at inappropriate times, such as on receiving a WM_SETFOCUS

message, and at other times when changing the internal state. This

often leads to strange looking displays, because controls draw all or

part of themselves at odd times. In Windows version 3.1, the controls

do not call UpdateWindow as often, which speeds up and improves the

appearance of window repainting.

Potential Problem

-----------------

Some controls may not get redrawn properly if they are moved or hidden

before they get a chance to process a WM_PAINT message.

Tests

-----

1. Minimize your application, and start another application. Restore

   your application. Be sure it paints correctly.

2. Start your application with another Windows-based application, such as

   one of the accessories. Bring the other application to the foreground,

   covering your application. Switch back to your application. Be sure it

   painted correctly.

3. Start several applications. Use ALT+TAB to switch between them. Be

   sure your application repaints correctly.

SCROLLING

---------

In a Windows version 3.0 application, the ScrollWindow function has a

number of bugs associated with scrolling a window that had any invalid

area. Frequently, the update region that results after the scrolling

operation is not properly calculated. In a Windows version 3.1

application, ScrollWindow calculates the update region correctly.

Potential Problem

-----------------

Any Windows version 3.0 application whose version number is changed to

3.1 may encounter problems if it works around the Windows version 3.0

bugs.

Test

----

Run your application and try a variety of scrolling operations.

MULTIPLE-DOCUMENT INTERFACE (MDI)

---------------------------------

For Windows 3.0 applications, MDI is completely compatible with

Windows 3.0. For Windows 3.1 applications, MDI has been enhanced. In

particular, specifying the low-order style bit (MDIS_ALLCHILDSTYLES)

when creating an MDICLIENT window enables the new Windows 3.1 MDI

capabilities for that window. This gives applications control over all

MDI child window styles and allows for hidden windows.

Potential Problem

-----------------

Any Windows 3.0 application whose version number is changed to 3.1 may

encounter problems if it unintentionally sets the low-order style bit

when creating an MDICLIENT window.

WINDOWS HOOKS

-------------

In Windows version 3.0, three hook functions are available:

SetWindowsHook, UnhookWindowsHook, and DefHookProc. In Windows version

3.1, three more-powerful functions replace these functions:

SetWindowsHookEx, UnhookWindowsHookEx, and CallNextHookEx. Microsoft

strongly recommends that a Windows version 3.1 application use the new

functions. The old functions are still supported for backward

compatibility.

In Windows version 3.0, an application or a DLL that installs a hook

must maintain the hook chain. In Windows version 3.1, Windows

maintains the hook chains. As a result, subtle changes in the

interface may affect Windows version 3.0 applications. Furthermore,

Windows version 3.1 no longer allows applications and DLLs to

enumerate all the functions in a hook chain. In particular, Windows

version 3.1 no longer supports the HC_GETLPLPFN, HC_LPLPFNNEXT, and

HC_LPFNNEXT values for the DefHookProc function.

In Windows version 3.0, SetWindowsHook returns a pointer to the next

hook function. In Windows version 3.1, SetWindowsHook does not return

a pointer; instead, it returns a 32-bit value that identifies the next

hook function.

Potential Problem

-----------------

An application that attempts to call the next hook function by using

the return value from SetWindowsHook as a function address will cause

a GP fault.

In Windows version 3.0, Windows passes negative hook values to hook

functions when unhooking a hook. These negative values are for Windows

internal use only. In Windows version 3.1, Windows does not pass

negative hook values to hook functions; it uses another method to

unhook a hook.

Potential Problem

-----------------

An application's hook function fails if it depends on receiving

negative hook codes to carry out specific tasks.

A Windows version 3.0 application can unhook a hook function by

passing the address of the next hook function to the SetWindowsHook

function. In Windows version 3.1, passing the address of the next hook

function causes a RIP in the Windows version 3.1 debugging version. In

Windows version 3.0, SetWindowsHook never fails and so never returns

an error value. In Windows version 3.1, SetWindowsHook can fail, and

when it does so, it returns the error value -1L.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsCompat


Windows 3.1 Application Compatibility (part 4 of 7)

Article ID: Q80899

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Application Compatibility Document for Windows 3.1

--------------------------------------------------

Due to the amount of information in this document, it has been broken

into seven pieces. To find all seven pieces of this document and the

Windows 3.1 Compatibility Test checklist, query this knowledge base on

the words:

   prod(winsdk) and 31compattest

PARAMETER VALIDATION

--------------------

Windows strictly checks parameters passed to its functions before

using them. In a Windows version 3.0 application, Windows works around

many validation errors and lets the function or application continue

to function. In a Windows version 3.1 application, many of these

errors cause the functions to fail, and the developer must ensure that

structures and parameters are passed correctly.

For example, in Windows version 3.0, if an application passes NULL as

the hInstance parameter to CreateWindowEx, Windows maps the handle to

the stack segment. In Windows version 3.1, the function returns an

error value.

The SDK release notes describe this in more detail. In some cases, the

system may reject valid parameters incorrectly and cause applications

to misbehave. Microsoft plans to correct any such occurrences.

UNDELETED OBJECT NOTIFICATIONS

------------------------------

In Windows version 3.1, any GDI or USER object left allocated when an

application terminates results in a warning to the debug terminal.

Windows version 3.1 does not automatically free these objects; the

application must free them. These warnings usually imply a memory

leakage; running and terminating an offending application eventually

uses up all available memory.

In some cases applications (and DLLs) allocate objects that are

intended to stay around longer than the application that created them.

This occurs frequently in shared DLLs that share GDI objects such as

bitmaps and brushes among their many clients. In such cases, ignore

the warnings at the debug terminal.

Potential Problem

-----------------

Applications can eventually use up available memory, which seriously

degrades system performance.

Test

----

Use the Program Manager to check memory usage before and after running

your application. Follow these steps:

1. Choose the About command in Program Manager's Help menu. Record the

   amount of available memory and resources.

2. Run your application and carry out enough tasks to ensure that one

   or more objects are created. Terminate your application.

3. Choose the About command again and compare available memory and

   resources. Be sure these values have not dropped.

4. Repeat this procedure several times, and check available memory and

   resources each time.

MENU IMPLEMENTATION

-------------------

Windows version 3.1 has enhanced menu management. In particular, the

TrackPopupMenu function allows additional parameters, and Windows

stores application menu data in a separate heap, expanding the number

of windows that may exist.

In Windows version 3.0 applications, Windows sends a WM_COMMAND

message using the SendMessage function. In Windows version 3.1

applications, Windows sends the message using the PostMessage

function, preventing the potential for overflowing a stack when

dealing with pop-up menus.

REGISTERCLASS

-------------

In Windows version 3.0, Windows fails to free the window-class

background brush properly when deleting the class. In Windows version

3.1, Windows frees the brush when either a Windows version 3.0 or 3.1

application terminates.

Potential Problem

-----------------

A multiple-instance application that deletes the background brush may

unintentionally delete a brush when other instances of the application

are running.

TOPMOST WINDOW

--------------

A new window attribute allows a window to be placed on top of all

other windows, even when the owning application is not active. If

multiple applications have topmost windows, the topmost window is

ordered the same as owning applications.

Also, a topmost window, its owners, and all windows it owns stay

together as windows are moved around. Thus, if you bring an owned

dialog window to the top, its owner is also brought forward so that it

stays immediately below the dialog box.

Potential Problem

-----------------

Applications that depend on being able to have windows of other

applications between their main window and a dialog box may encounter

problems. For example, a Setup program that starts Notepad and then

brings up a dialog box causes Notepad to be positioned behind the

dialog box owner. The solution is to create the dialog box without an

owner (a window may not be owned by a window of another application).

Potential Problem

-----------------

Any application that relies on having an unobstructed client area when

active may encounter problems because the active window cannot be

guaranteed to be on top. Thus, the active window may not have a

rectangular clipping region because a topmost window may be on top of

it. Calling BitBlt with a window or screen DC as the source (which is

not recommended in any case) may copy bits belonging to the topmost

window.

Tests

-----

1. Examine your application code, and be sure there are no

   dependencies on client area visibility when your application is

   active.

2. Start the clock, and set it to be the topmost window. Run your

   application and several others. Use ALT+TAB to switch between

   applications, and be sure your application repaints correctly.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsCompat


Windows 3.1 Application Compatibility (part 5 of 7)

Article ID: Q80900

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Application Compatibility Document for Windows 3.1

--------------------------------------------------

Due to the amount of information in this document, it has been broken

into seven pieces. To find all seven pieces of this document and the

Windows 3.1 Compatibility Test checklist, query this knowledge base on

the words:

   prod(winsdk) and 31compattest

                               TrueType

                               ========

Although Windows version 3.1 includes support that seamlessly

integrates TrueType fonts into existing applications, problems with

fonts can occur for Windows version 3.0 applications that assume

bitmap fonts are always available, that Helv and Tms Rmn are always

available, and that font sizes are limited. Be sure to thoroughly

check fonts in your application, including files and dialogs. Also,

because TrueType provides more fonts at more sizes and in more styles,

Windows version 3.1 may consume both printer and global memory faster

than Windows version 3.0 did. Check your applications with systems and

printers that have limited memory.

HELV AND TMS RMN FONTS

----------------------

MS Sans Serif replaces Helv, and MS Serif replaces Tms Rmn. To support

Windows version 3.0 applications that use the Helv and Tms Rmn fonts,

the [FontSubstitutes] section in the WIN.INI file maps Helv to MS Sans

Serif and Tms Rmn to MS Serif by default. It also maps Times to Times

New Roman and Helvetica to Arial.

Potential Problem

-----------------

Applications that hard code a search for Helv or Tms Rmn may encounter

difficulties after not finding these fonts.

Test

----

Examine your application code and be sure there are no dependencies on

the font names Helv and Tms Rmn.

FONT ENUMERATION

----------------

Applications should test to ensure that TrueType fonts are enumerated

correctly and that they encounter no unexpected font mapping, such as

might occur when a TrueType font substitutes for another font and line

spacing changes and/or the position of text in documents is

recalculated.

Windows continues to support and is fully backward compatible with

ATM, Facelift, and Intellifont for Windows. Applications using these

other font technologies should encounter no problems.

TRUETYPE ONLY CHECKED

---------------------

Windows version 3.0 applications may behave unexpectedly if the user

has set the "Show Only TrueType Fonts in Applications" check box using

the Control Panel.

Potential Problem

-----------------

An application may fail to locate any fonts if only TrueType fonts are

present.

Test

----

In the Control Panel, choose Fonts, select TrueType, and enable "Show

Only TrueType Fonts in Applications."

 - Check the font dialog boxes in your application. It should list all

   the TrueType fonts and should not list non-TrueType fonts.

FONT SIZES

----------

TrueType supports a wide variety of sizes for all TrueType fonts. In

Windows version 3.1, an application usually gets the requested size if

it requests a very small or very large font.

Potential Problem

-----------------

An application that checks for the smallest or largest font by setting

the nHeight parameter in CreateFont to an extreme value will not get

the expected results.

Test

----

Check fonts in dialog boxes, tool bars, and sample files for your

application. Be sure they are all readable.

FONTSUBSTITUTES

---------------

The [FontSubstitutes] section may cause the GetTextFace function to

return a face name that the EnumFonts function does not enumerate.

This is done so that an application that asks for Helv (and expects

Helv) gets a font named Helv.

Potential Problem

-----------------

An application that expects matching face names from the EnumFonts and

GetTextFace functions may encounter mismatches.

Test

----

Check the application code and be sure there are no dependencies on

GetTextFace and EnumFonts matching.

ABC-SPACED FONTS

----------------

Potential Problem

-----------------

ABC-spaced fonts can lead to misplaced cursors, highlights that do not

encompass all the text on a line, "pieces" of characters left behind

after screen updates, and unexpected clipping of fonts on printers

(when a character goes outside the printable area).

Tests

-----

1. Create a document in your application that contains characters

   close to the edge of the screen and the printable margins. Scroll

   the document, checking for characters (or pieces of characters)

   left behind.

2. Highlight text. Be sure the highlight encompasses all characters

   and that no part of any character (especially the first and last

   characters) is left out.

3. Print the document. Be sure that no characters are clipped at the

   edges of the printable region.

THIRD-PARTY TYPE MANAGER PROBLEMS

---------------------------------

Potential Problem

-----------------

Be sure to try your application with ATM, Facelift, or Intellifont for

Windows fonts installed. Do not install more that one of these font

managers at a time. Skip this test if your application does not work

with these font managers under Windows version 3.0a.

Tests

-----

1. Create a document under Windows version 3.0a using a type manager

   (such as ATM), bitmap, and device fonts. Look at the document under

   Windows version 3.1, and be sure the screen appears the same.

2. Print the document with Windows versions 3.0a and 3.1, and be sure

   the output is identical.

FONT ENUMERATION

----------------

Windows version 3.0 applications sometimes create multiple instances

of a single font or font family. In particular, some applications

handle fonts that a nonraster printer enumerates as different from

fonts enumerated for the display, even if the names are the same.

TrueType fonts with the same name are identical regardless of the

output device. Some Windows version 3.0 applications assume that

scalable fonts cannot be available on nonscaling devices. In such

cases, the applications intentionally enumerate a single size for

every TrueType font even though other sizes are available.

Furthermore, some applications assume that bold, italic, and bold

italic are always simulated from regular fonts. This is not true with

TrueType fonts.

Potential Problem

-----------------

An application may create multiple instances of the same font.

Tests

-----

1. If your application assumes that scalable fonts could not print on

   nonscalable devices, such as a PCL printer, it will have problems

   enumerating fonts. Check the font dialog boxes and sizes listed for

   TrueType fonts. Many sizes for each TrueType font should be listed.

2. TrueType fonts are shipped in regular, bold, italic, and bold

   italic. This can cause problems for applications that assume styles

   were always simulated. Check the font dialog boxes to be sure that

   each font is listed only once.

3. TrueType fonts appear for both printer and screen. This causes

   problems for applications that assume printer and screen fonts are

   always different. Select a nonraster printer (for example, PCL) and

   check the font dialog boxes to be sure each font is listed only

   once.

MIXING DEVICE, BITMAP, AND TRUETYPE FONTS

-----------------------------------------

In Windows version 3.1, some fonts, such as the Symbol font, may be

supported by a TrueType font, a GDI bitmap font, and a device-specific

font. Applications can get unexpected results when printing

waterfalls. For example, a Symbol waterfall to a dot matrix printer

intermixes the Symbol bitmap with TrueType Symbol. Because no Symbol

font is designed for dot matrix resolution, the results can be

spectacularly unattractive.

Potential Problem

-----------------

Printing may mix device, bitmap, and TrueType fonts causing

unacceptable output.

Test

----

Create a document with a nonscalable printer installed, using a device

font and a TrueType font. Both fonts must have the same name. Print.

DESKTOP PUBLISHING AND INTERNATIONAL CHARACTERS

-----------------------------------------------

Windows version 3.1 includes 22 new international and desktop

publishing characters. Unfortunately, these new characters appear only

in TrueType fonts; the bitmap fonts do not have them.

Potential Problem

-----------------

Changing to a bitmap font causes the new characters to appear as

"blots." Some applications may remap the character code range (128 to

159).

Tests

-----

1. Use a TrueType font to create a document using the desktop

   publishing and international characters. Be sure the characters

   appear correctly on the screen.

2. Select a bitmap font, and then change to a TrueType font. Be sure

   the characters still appear correctly.

3. Print the document. Be sure the printout is correct.

4. Using the Char Map application in the Accessories group of Program

   Manager, use a TrueType font to copy the desktop publishing

   characters to the clipboard and paste them into your application.

   Be sure the characters appear correctly.

NOTE: The desktop publishing characters will not be available to

dialog boxes that use bitmap fonts exclusively (such as the Find and

Replace dialog boxes).

TEXT ROTATION

-------------

Although Windows version 3.0 can rotate vector and device fonts, under

certain mapping modes it rotates these fonts differently. For

compatibility, Windows version 3.1 also rotates fonts differently.

However, an application can override this default behavior and direct

Windows version 3.1 to rotate all fonts the same by setting the

CLIP_LH_ANGLES bit in the lfClipPrecision member of the LOGFONT

structure. When this bit is set, Windows version 3.1 rotates all fonts

using the same left-hand rule as Windows version 3.0 uses to rotate

device fonts.

OTHER CONSIDERATIONS

--------------------

 - Some applications do not request point sizes correctly. For bitmap

   fonts, the results are acceptable because only these fonts have a

   limited range of sizes available. For TrueType fonts, output can be

   unacceptable because any size requested is available.

 - Applications sometimes set the tmCharWidth to request specific

   fonts, but Windows now stretches or compresses a TrueType font to

   match the requested width. Some applications make assumptions that

   work for bitmaps in many cases but that lead to squashed or clipped

   lines with TrueType fonts.

 - Windows version 3.1 adds 13 or more fonts to the default list. Some

   applications may break when more fonts of more types in more styles

   are enumerated. They do not have test cases that can account for

   the additional fonts.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsCompat


Windows 3.1 Application Compatibility (part 6 of 7)

Article ID: Q80901

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Application Compatibility Document for Windows 3.1

--------------------------------------------------

Due to the amount of information in this document, it has been broken

into seven pieces. To find all seven pieces of this document and the

Windows 3.1 Compatibility Test checklist, query this knowledge base on

the words:

   prod(winsdk) and 31compattest

                        Enhanced-Mode Windows

                        =====================

COMM DRIVER

-----------

Performance and functionality of the Windows version 3.1 COMM driver

are improved as follows:

 - COMM.DRV provides its own interrupt handling in enhanced mode. In

   Windows version 3.0, the virtual communication device (VCD)

   provided the interrupt routine so that interrupts for Windows

   applications could be handled at ring 0. In Windows version 3.1, a

   new function allows COMM.DRV to register its own ring-0 handler,

   ensuring that all communications code exists in COMM.DRV. The VCD

   can still support COMM drivers that are compatible with Windows

   version 3.0 by adding the SYSTEM.INI switch "COMMDRV30=TRUE" in the

   [386ENH] section.

 - Both COMM.DRV and VCD read the COMxBASE and COMxIRQ settings in the

   SYSTEM.INI file to determine the base addresses and IRQs for COM3

   and COM4; reading values written into the BIOS data area is no

   longer required. Although for compatibility these settings are in

   the [386ENH] section, COMM.DRV also examines them when running in

   standard mode.

 - COMM.DRV supports the FIFO on 16550A UARTs. By default, COMM.DRV

   enables the FIFO if the FIFO is available, but the user can disable

   the FIFO by using the COMxFIFO setting in the [386ENH] section of

   the SYSTEM.INI file.

 - COMM.DRV baud rate is limited only by machine capability, so

   communication applications need not limit baud rates to 19200. Some

   users do have hardware capable of faster rates, and they don't like

   being stuck with an artificial limit.

Potential Problem

-----------------

Changes to COMM.DRV could affect any application that uses the

communications driver.

Test

----

You can test most changes to COMM.DRV by sending and receiving data in

your application at various baud rates.

VIRTUAL PRINTER DEVICE

----------------------

The standard setup no longer includes the virtual printer device

(VPD). In Windows version 3.0, the VPD detects contention between

multiple VMs attempting to access the same LPT port. To detect

contention, VPD traps I/O for LPT ports, which creates too much

overhead for devices that use LPT ports, such as network adapters,

SCSI adapters, and external hard disks. Windows version 3.1 eliminates

the overhead by not installing the VPD.

Potential Problem

-------------------

Although changes to the virtual printer device installation should not

affect applications, Windows version 3.1 cannot detect the rare case

of two applications attempting to print through the same port at the

same time.

VIRTUAL DMA DEVICE

------------------

In Windows version 3.1, VDMAD supports auto-initialize DMA as long as

the region being used can be locked and does not have alignment

problems. This means that TSRs and device drivers can use auto-

initialize DMA with global memory. VDMAD also deals with DMA globally

rather than through VM. This means that most global users (network,

disk, and so on) no longer need a separate virtual device to

coordinate their DMA activity when they set up DMA transfers using

hardware interrupts. Finally, all problems in the virtual DMA services

implementation have been corrected; relying on private versions of

VDMAD is no longer necessary.

Potential Problem

-----------------

Changes to the VDMAD may affect applications that include their own

version of VDMAD.

Test

----

If your application has a custom VDMAD, thoroughly test the

application with the new VDMAD. Also, be sure that your installation

program does not overwrite the device=*VDMAD setting in the SYSTEM.INI

file.

VIRTUAL TIMER DEVICE

--------------------

In Windows version 3.1, the virtual timer device (VTD) does not trap

the I/O ports used for accessing the system timer chip. This allows

more MS-DOS software to run better in VMs because I/O trapping adds

significant overhead. The VTD keeps timing in sync by watching other

activity, for example, by counting hardware interrupts that are not

passed to the BIOS. Thus, the VTD does not prevent applications from

reprogramming the timer to different rates. The TrapTimerPorts setting

was added to the SYSTEM.INI file to revert to Windows version 3.0

compatible behavior if problems do occur because of this change.

Potential Problem

-----------------

Changes to the virtual timer device may affect applications that are not

based on Windows.

Test

----

Start several other MS-DOS-based applications, and then start your MS-DOS-

based application and check for timer problems. If problems arise,

set the SYSTEM.INI setting TrapTimerPorts and try the tests again.

VIRTUAL DISPLAY DEVICE

----------------------

In Windows version 3.1, the standard virtual display device (VDD) for

VGA is modified to demand page video memory. Thus, you can run

graphical MS-DOS-based applications in a window or in the background on VGA

systems. This VDD must track video memory usage, so it is not

compatible with any of the super VGA display drivers that must access

more than 256 kilobytes (K) of video memory. To run these display

drivers, a user must use either the VDD provided by the display

adapter manufacturer or the VDDVGA30.386, which is included with

Windows version 3.1. Demand paging of video memory may break TSRs that

worked with Windows version 3.0. The difference is that the VDD

virtualizes access to video memory; in Windows version 3.0, the

display driver had full reign over memory.

Potential Problem

-----------------

Changes to the video device driver may affect applications that work

directly with video memory and TSRs.

Test

----

Start your application or TSR in one or more virtual machines, and

then switch between virtual machines, watching for problems with the

display.

FASTDISK (WDCTL)

----------------

FastDisk allows specific virtual devices (currently WDCTL) to access

secondary storage devices directly. WDCTL supports Western Digital and

compatible controllers. This device speeds up disk activity and allows

demand paging of running VMs.

Test

----

FastDisk should not affect any applications. Be sure you are running

it while testing your application.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsCompat


Compatibility Test For Windows 3.1 Checklist

Article ID: Q80903

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

This document provides the checklist that corresponds to the seven

articles titled "Windows 3.1 Application Compatibility." When you

follow the steps to test your application, load this document into a

word processor and complete the information requested. When testing is

complete, print this document and mail it, along with the printing

tests requested, to the address listed at the bottom of this document.

To find the "Windows 3.1 Application Compatibility" articles, search

this knowledge base on the words:

   prod(winsdk) and 31compattest

Please be candid in your responses. We value your feedback.

The names of up to three people involved in testing the application

for compatibility can be entered into the Windows 3.1 Compatibility

Sweepstakes.

Application Name:

Version:

Shipment Date:

Company Name:

Address:

Representative: *

Phone:

Fax:

* Please name the person that Microsoft should contact with

information regarding the test results or problems.

General Instructions

====================

Try each operation listed in each section (if it applies to your

application). Please include a description of the operations you tried

in the Comments section. Also include information about why you didn't

try an operation if this is the case.

Application Installation Programs

=================================

___Pass ___Fail Run your installation program from the MS-DOS prompt.

___Pass ___Fail Run your installation program from the MS-DOS prompt

                under Windows.

___Pass ___Fail Run your installation program from the Run command in

                the File menu of Program Manager.

Comments:

Windows Setup

=============

___Pass ___Fail Install Microsoft Windows version 3.1 on a computer

                with Windows version 3.0a and your application already

                installed. Be sure to preserve your application's

                WIN.INI and Program Manager settings.

Comments:

Shell Application

=================

___Pass ___Fail Run your application as the shell. Exit Windows and be

                sure that Windows terminates correctly.

Comments:

Windows Shell Applications

==========================

___Pass ___Fail Start your application from File Manager.

___Pass ___Fail Start your application from Program Manager.

___Pass ___Fail Start your application from the Startup group (copy

                your application's icon to the group and restart

                Windows).

___Pass ___Fail Start your application without the network installed.

___Pass ___Fail Start your application with the network installed.

___Pass ___Fail Drag a file from File Manager to your application.

___Pass ___Fail Drag a file associated with your application to Print

                Manager.

___Pass ___Fail Check colors in your application when the system has

                default colors.

___Pass ___Fail Check colors in your application when the system has

                nondefault colors (for example, Arizona).

___Pass ___Fail Check colors in your application when the system

                colors are customized.

___Pass ___Fail Use Windows version 3.1 Cardfile and Write to open and

                view files that your application created.

___Pass ___Fail Use your application to open and read files that

                Windows version 3.1 Cardfile and Write created and

                that contain OLE objects.

Comments:

Multimedia and Sound

====================

___Pass ___Fail Check all of your application's sound capabilities

                when running in a virtual machine.

___Pass ___Fail Exit Windows and check all of your application's sound

                capabilities when running under MS-DOS.

___Pass ___Fail Check all of your application's sound capabilities.

___Pass ___Fail Check all of your application's capabilities that

                unusual drivers supply.

Comments:

Window Management

=================

___Pass ___Fail Start your application in its default state. Maximize

                and minimize it, making sure it paints correctly after

                each operation.

___Pass ___Fail Move your application as far right and left as you can

                in small increments, watching for repaint problems

                each time you stop moving.

___Pass ___Fail Resize your application using the mouse to drag the

                border.

___Pass ___Fail Minimize your application, starting another

                application. Restore your application. Be sure it

                paints correctly.

___Pass ___Fail Start your application with another Windows

                application, such as one of the accessories. Bring the

                accessory to the foreground, covering your

                application. Switch back to your application. Be sure

                it painted correctly.

___Pass ___Fail Start several applications. Use ALT+TAB to move

                through them. Be sure your application repaints

                correctly.

___Pass ___Fail Check all of your application's scrolling capabilities.

___Pass ___Fail Use the Program Manager to check memory and resource

                usage before and after running your application. Be

                sure available memory and resources are not lost.

___Pass ___Fail Examine your application code, and be sure there are

                no dependencies on client area visibility when your

                application is active.

___Pass ___Fail Start the clock and set it to be the topmost window.

                Run your application and several others. Use ALT+TAB

                to switch between applications, and be sure your

                application repaints correctly.

Comments:

TrueType

========

___Pass ___Fail Examine your application code and be sure there are no

                dependencies on the font names Helv and Tms Rmn.

___Pass ___Fail Enable the "Show Only TrueType Fonts in Applications"

                option in Control Panel. Check the font dialogs in

                your application. They should list all TrueType fonts

                and no non-TrueType fonts.

___Pass ___Fail Check fonts in dialog boxes, tool bars, and sample

                files for your application. Be sure they are readable.

___Pass ___Fail Check the application code and be sure there are no

                dependencies on GetTextFace and EnumFonts matching.

___Pass ___Fail Create a document in your application that contains

                characters close to the edge of the screen and the

                printable margins. Scroll the document, checking for

                characters (or pieces of characters) left behind.

___Pass ___Fail Highlight text. Be sure the highlight encompasses all

                characters and that no part of any character

                (especially the first and last characters) is left

                out.

___Pass ___Fail Print the document. Be sure no characters are clipped

                at the edges of the printable region.

___Pass ___Fail Create a document under Windows version 3.0a using

                type-manager (such as ATM), bitmap, and device fonts.

                Look at the document under Windows version 3.1; be

                sure the screen appears the same.

___Pass ___Fail Print the document under Windows versions 3.0a and

                3.1; be sure the output appears the same.

___Pass ___Fail If your application assumed that scalable fonts could

                not print on nonscalable devices, such as a PCL

                printer, it will have problems in enumerating fonts.

                Check the font dialog box and sizes listed for TrueType

                fonts. The font dialog box should list many sizes for each

                TrueType font.

___Pass ___Fail TrueType fonts are shipped in regular, bold, italic,

                and bold italic. This can cause problems for

                applications that assumed styles were always

                simulated. Check the font dialog box to ensure that each

                font is listed only once.

___Pass ___Fail TrueType fonts appear for both printer and screen.

                This causes problems for applications that assume

                printer and screen fonts are always different. Select

                a nonraster printer (for example, PCL) and check the

                font dialog box to ensure that each font is listed only

                once.

___Pass ___Fail Create a document with a nonscalable printer

                installed, using two fonts, a device font, and a

                TrueType font. Both fonts must have the same name.

                Print the document.

___Pass ___Fail Use a TrueType font to create a document using the

                desktop publishing and international characters. Be

                sure the characters appear correctly on the screen.

___Pass ___Fail Change to a bitmap font, and then change back to a

                TrueType font. Be sure the characters still appear

                correctly.

___Pass ___Fail Print the document. Be sure the printout is correct.

___Pass ___Fail Using the Char Map application in the accessories

                group of Program Manager, use a TrueType font to copy

                the desktop publishing characters to the clipboard and

                paste them into your application. Be sure the

                characters appear correctly.

Comments:

Enhanced-Mode Windows

=====================

___Pass ___Fail Check COMM.DRV by sending and receiving data in your

                application at various baud rates.

___Pass ___Fail Check the new VDMAD as a replacement for your custom

                VDMAD by thoroughly testing your application with the

                new VDMAD.

___Pass ___Fail Check your application's installation program to

                ensure that it does not overwrite the "device=*VDMAD"

                setting in the SYSTEM.INI file.

___Pass ___Fail Check the VTD by starting several other non-Windows

                applications and then starting your non-Windows

                application. Check for timer problems. If there are

                problems, set the SYSTEM.INI setting TrapTimerPorts

                and try the tests again.

___Pass ___Fail Check the VDD by starting your application or TSR in

                one or more virtual machines and then switch between

                virtual machines watching for problems with the

                display.

___Pass ___Fail Check Fastdisk by running it while testing your

                application.

Comments:

Printing

========

___Pass ___Fail Print using the PostScript driver.

___Pass ___Fail Print using the LaserJet II driver.

___Pass ___Fail Print using the LaserJet III driver.

___Pass ___Fail Print using the dot-matrix driver.

___Pass ___Fail Bring a document created under Windows version 3.0a

                with your application to version 3.1 and print it. Be

                sure there are no error messages and that it prints

                correctly.

___Pass ___Fail Check you application code for the GETTEXTENTTABLE

                escape.

Please include the documents you printed when returning this form to

Microsoft.

Comments:

SmartDrive 4

============

___Pass ___Fail Read files from disk.

___Pass ___Fail Write files to disk.

___Pass ___Fail If your application uses the floppy drive or can read

                and write files to the floppy drive, try those

                operations with caching enabled on the floppy.

Comments:

Local CTRL+ALT+DEL

==================

___Pass ___Fail Press CTRL+ALT+DEL while your application is running.

                Be sure Windows continues to function after your

                application terminates.

Comments:

Checklist of Problem Areas Not Specific to Windows 3.1 Changes

--------------------------------------------------------------

Following are some areas that you should check, but that were not

changes for Windows version 3.1. We have seen several applications

with problems in these areas.

Setup

=====

___Pass ___Fail Try your setup program with SHARE enabled and not

                enabled. Be sure your setup program runs correctly in

                both cases.

___Pass ___Fail Install Windows version 3.1 over Windows version 3.0,

                but in a directory other than the one containing

                Windows version 3.0. Be sure your application runs

                under Windows version 3.1 without being reinstalled.

___Pass ___Fail Try your setup program with a path that is at the

                maximum length. Be sure your setup program recognizes

                that it cannot add to the path.

___Pass ___Fail Try your setup program with an AUTOEXEC.BAT file

                containing more than one path statement, or by calling

                batch files that set the path. Be sure your setup

                program recognizes the correct path statement to which

                to add information.

___Pass ___Fail Try your setup program with a screen saver running.

___Pass ___Fail Install your application on a hardcard drive and on a

                compressed drive. Be sure the application installs and

                runs correctly.

___Pass ___Fail Install your application on a hard drive with a drive

                letter greater than E:. Be sure your application

                installs and runs correctly.

___Pass ___Fail If your application can be installed on a network,

                install it on as many networks as possible.

Comments:

General Operations

==================

___Pass ___Fail Load a large file, and resize the application window

                so that scrolling is necessary horizontally and

                vertically. Scroll and ensure that repainting is

                correct.

___Pass ___Fail Exit Windows while your application is still running

                but has unsaved files. Be sure you are prompted to

                save the unsaved files before Windows exits.

___Pass ___Fail Run your application with SHARE enabled and not

                enabled. Be sure it runs correctly.

___Pass ___Fail If your application adds anything to AUTOEXEC.BAT that

                uses environment space, be sure the application works

                or dies gracefully if the machine is out of

                environment space.

___Pass ___Fail Have the default printer in the Control Panel

                different from the printer selected in your

                application, and print a document. Be sure your

                application prints correctly or that it warns the user

                of the condition.

___Pass ___Fail Create a directory using character ASCII 129

                (ALT+129). Using your application's File Open or File

                Save commands, change to this directory.

Comments:

Please enter the names of three people who have performed the testing

and want to be eligible for the Windows 3.1 Compatibility Sweepstakes:

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Name:

Address for possible delivery:

Phone:

Title:

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Name:

Address for possible delivery:

Phone:

Title:

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Name:

Address for possible delivery:

Phone:

Title:

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

RETURN YOUR COMPLETED TEST TO:

   Windows Compatibility Test

   Microsoft Corporation

   One Microsoft Way

   Building 4

   Redmond, WA  98052-6399

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsCompat


An Annotated Dr. Watson Log File

Article ID: Q81142

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Dr. Watson is a utility that logs information about applications that fail.

This article presents a sample log file and explains what the various

entries signify. Comments in the log file start with pound sign (#).

This article annotates a log file for the BICHO application, which tests

Windows by faulting in the various ways. Bicho is Bolivian slang for "bug"

or "critter."

MORE INFORMATION

================

# Dr. Watson writes the following line each time it starts execution

# unless the [dr. watson] section of the WIN.INI file contains the

# line SkipInfo=time:

Start Dr. Watson 0.80 - Thu Sep 26 10:51:28 1991

# These lines mark the beginning of a Dr. Watson failure report

# They report the version of Dr. Watson and the date and time of the

# reported event.

**********************************************************************

Dr. Watson 0.80 Failure Report - Thu Sep 26 10:51:36 1991

# The next line reports that an application named "BICHO" encountered

# an "Exceed Segment Bounds" fault while reading memory. The precise

# point of failure was also in BICHO, 0x6b bytes after the start of

# the DoCommand function.

BICHO had a 'Exceed Segment Bounds (Read)' fault at BICHO

_DoCommand+006b

# The following line repeats the previous information formatted for

# automatic parsing code. It also includes the instruction that caused

# the fault (a push instruction in this case).

$tag$BICHO$Exceed Segment Bounds (Read)$BICHO _DoCommand+006b$push

word ptr [fffe]$Thu Sep 26 10:51:36 1991

# The following lines report the contents of the CPU registers:

CPU Registers (regs)

# The 16-bit registers are listed first. This information can be

# useful to determine what address an instruction modified when the

# fault occurred.

ax=1e54  bx=0014  cx=0d7f  dx=0111  si=1e54  di=0111

# The next items are the instruction pointer (otherwise known as the

# program counter), stack pointer, and base pointer. This line also

# lists the state of the flag bits. In this example, the Overflow,

# Direction, Sign, Zero, and Carry bits are Clear (0), while the

# Interrupt, Auxcarry, and Parity bits are Set (1).

ip=02fd  sp=230c  bp=237a  O- D- I+ S- Z- A+ P+ C-

# The code segment selector is 0e57, linear address is 8059fbc0. The

# code segment's limit is 83f. (Enhanced mode linear addresses often

# start with 8xxx.) Accessing a code or data segment beyond its limit

# is a common cause of GP faults.

cs = 0e57  8059fbc0:083f Code Ex/R

# The next line provides information about the stack segment selector.

ss = 0d7f  8059d5e0:25df Data R/W

# The following line provides information about the data segment

# selector. Note that the limit is 25df, while the application

# attempted to read the value at fffe, which is beyond the segment's

# limit.

ds = 0d7f  8059d5e0:25df Data R/W

# The following line provides information about the extra segment

# selector:

es = 0d7f  8059d5e0:25df Data R/W

# The next lines provide information about the 32-bit registers.

# If a selector is 0, it corresponds to the null pointer. Attempting

# to use a null pointer is another common cause of GP faults.

CPU 32 bit Registers (32bit)

eax = 00001e54  ebx = 00000014  ecx = ffff0d7f  edx = 00000111

esi = 00001e54  edi = 00000111  ebp = 0000237a  esp = 800422fc

fs = 0000         0:0000 Null Ptr

gs = 0000         0:0000 Null Ptr

eflag = 00000002

# The next lines provide information about the Windows installation.

System Info (info)

Windows version 3.10

Debug build  # The debug version of windows (from the SDK) was running

Windows Build 3.1.048 # This is a prerelease build of Windows, #48

Username Unknown User               # Your Name Here

Organization Unknown Organization   # Your Organization Here

System Free Space 7131008

# The following provides the stack size for the current task:

Stack base 1122, top 9164, lowest 7504, size 8042

# Dr. Watson records some statistics about the Windows environment:

System resources:  USER: 87% free, seg 0777  GDI: 85% free, seg 05d7

LargestFree 6594560, MaxPagesAvail 1610, MaxPagesLockable 267

TotalLinear 1948, TotalUnlockedPages 274, FreePages 52

TotalPages 614, FreeLinearSpace 1611, SwapFilePages 7158

Page Size 4096

4 tasks executing.

WinFlags -

  Math coprocessor

  80386 or 80386 SX

  Enhanced mode

  Protect mode

# The following records the contents of the stack to determine what

# code called the routine that failed:

Stack Dump (stack)

# Stack frame 0 indicates that the failure occurred in BICHO, 0x6b

# bytes after the start of the DoCommand function, as reported

# earlier.

Stack Frame 0 is BICHO _DoCommand+006b        ss:bp 0d7f:237a

# The offending instruction is disassembled in context, as follows:

0e57:02f0  e9 02b9               jmp    near 05ac

0e57:02f3  6a 00                 push   00

0e57:02f5  9a 8db0 0477          callf  0477:8db0

0e57:02fa  e9 02af               jmp    near 05ac

(BICHO:_DoCommand+006b)

0e57:02fd  ff 36 fffe            push   word ptr [fffe]

0e57:0301  68 0110               push   0110

0e57:0304  e8 fe5d               call   near 0164

0e57:0307  83 c4 04              add    sp, 04

# The application tried to read a value from memory at address DS:fffe

# and to push that value on the stack. However, the limit of the DS

# segment is 25df. The next stack frame documents that the BICHO

# application MainWndProc called DoCommand:

Stack Frame 1 is BICHO MAINWNDPROC+0027       ss:bp 0d7f:2388

0e57:0670  eb 16                 jmp    short 0688

0e57:0672  ff 76 0a              push   word ptr [bp+0a]

0e57:0675  56                    push   si

0e57:0676  e8 fc19               call   near 0292

(BICHO:MAINWNDPROC+0027)

0e57:0679  83 c4 04              add    sp, 04

0e57:067c  99                    cwd

0e57:067d  eb 1f                 jmp    short 069e

0e57:067f  6a 00                 push   00

# "USER" in the next stack frame is the Windows module USER.EXE. It

# calls application window and dialog procedures. In this case, USER

# called the BICHO application's MainWndProc.

Stack Frame 2 is USER IDISPATCHMESSAGE+007e   ss:bp 0d7f:239e

# In the next stack frame, the BICHO application's WinMain function

# called DispatchMessage, which called MainWndProc.

Stack Frame 3 is BICHO WINMAIN+0050           ss:bp 0d7f:23bc

# In the last stack frame, the Windows start-up code calls the

# application's WinMain function.

Stack Frame 4 is BICHO 1:00a3                 ss:bp 0d7f:23ca

# The next lines list all the tasks running in the system when the

# fault occurred. Dr. Watson itself, the shell application, and the

# faulting application will always be included.

System Tasks (tasks)

Task  WINEXIT, Handle 0daf, Flags 0001, Info    9248 08-09-90 16:52

  FileName C:\MS\WIN\DON\WINEXIT.EXE

Task DRWATSON, Handle 0ea7, Flags 0001, Info   26256 09-23-91 12:00

  FileName C:\WIN31\DRWATSON.EXE

Task  PROGMAN, Handle 060f, Flags 0001, Info  110224 09-23-91 12:02

  FileName C:\WIN31\PROGMAN.EXE

Task    BICHO, Handle 0da7, Flags 0001, Info   16537 09-11-91  8:45

  FileName D:\BICHO.EXE

# The last part of a failure report is any information typed in the

# "Dr. Watson's Clues" dialog box.

1> I ran a test app that accessed a value

2> beyond the limits of the segment bounds.

# Dr. Watson writes this line when it shuts down.

Stop Dr. Watson 0.80 - Thu Sep 26 10:52:10 1991

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsDrWatson


PRB: Two Builds of Same Windows Help File Not Identical

Article ID: Q81992

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

Help (.HLP) files generated from the same RTF source with the same

version of the Windows Help Compiler are not identical. Even though

the files work identically, a binary comparison of the file reveals

differences.

CAUSE

=====

Each Help file contains a time stamp indicating the compilation

time, and contains buffers that have some uninitialized data.

STATUS

======

This behavior results from design decisions made regarding Windows

Help and is unlikely to change for the foreseeable future.

Additional reference words: 3.00 3.10 HC HC.EXE

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


Introduction to STRICT and Message Crackers

Article ID: Q83456

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The WINDOWS.H and WINDOWSX.H header files in version 3.1 of the

Microsoft Windows Software Development Kit (SDK) provide new features

to make developing applications for the Windows environment faster and

easier. These features enable the C compiler to find many common

programming errors at compile time.

This article provides an overview and examples of the new features, as

well as a road map to other resources in the SDK that explain them.

MORE INFORMATION

================

The WINDOWS.H and WINDOWSX.H header files provide the following

features:

 - New data types and their associated definitions

 - A preprocessor variable, STRICT, which enforces the strictest

   possible type checking by the compiler

 - Macros to simplify many common operations in Windows programming

 - Control macros to simplify communication with Windows controls

 - Message crackers (which are a convenient, portable, and type-safe

   method to handle messages) and their associated parameters and

   return values in the Windows environment

The new types and STRICT type checking are implemented in the

WINDOWS.H file; the macros, control macros, and message crackers are

implemented in WINDOWSX.H. The Windows SDK installation program copies

each of these files into the include directory (by default,

C:\WINDEV\INCLUDE).

The SDK also provides the following resources:

 - WINDOWS.TXT, which explains the new types and STRICT features

   provided by WINDOWS.H.

 - WINDOWSX.TXT, which explains the macros, control macros, and

   message crackers provided by WINDOWSX.H.

 - MAKEAPP sample application, which uses all the new features of

   WINDOWS.H and WINDOWSX.H. MAKEAPP can create application templates

   that use all the new features.

 - MAKEAPP.TXT, which explains how to use MAKEAPP as an application

   template generator.

Any new code developed for Windows should use the new data types and

define the STRICT preprocessor variable. Doing so provides powerful

type checking and enables the C compiler to find many problems at

compile time.

Using the macros, control macros, and message crackers assists in the

process of finding errors and increases code portability; however,

using these features is a matter of taste. Some developers like them

and find them useful, others do not.

The simplest way to become familiar with the new features is to review

the WINDOWS.H and WINDOWSX.H header files, the associated WINDOWS.TXT

and WINDOWSX.TXT text files, and the MAKEAPP sample application. Each

of the new features is implemented in one of the header files (usually

as a fairly simple macro) and is explained in one of the text files.

Each of the new features is designed to address three goals:

 - Make the source code for an application easier to read

 - Enable the C compiler to catch programming errors

 - Ease porting to 32-bit Windows

In general, the new features can be used as appropriate throughout an

application. Some of the code can use traditional methods and other

code can use various combinations of the new features. The one

exception to this is the STRICT preprocessor variable--if STRICT is

defined in any source module, the entire module must be "STRICT

compliant" before it will compile successfully.

Each of the new features is compatible with Windows 3.0. You can use

the new features in an application that will run under version 3.0 and

you can modify existing code to use the new features.

The remainder of this article provides an introduction to each of the

new features.

New Data Types, Type Definitions, and Helper Macros

---------------------------------------------------

The new data types are implemented in WINDOWS.H and described in

WINDOWS.TXT. Examples of new data types are WPARAM, LPARAM, and UINT.

Examples of new handle types are HINSTANCE, HMODULE, and HTASK. Using

the new data types can make source code easier to read and simplify

porting to 32-bit Windows.

STRICT Preprocessor Variable

----------------------------

The STRICT preprocessor variable is implemented in WINDOWS.H and

described in WINDOWSX.TXT. When an application defines STRICT, the C

compiler enforces the highest possible level of type checking, which

enables the compiler to find as many errors as possible. It is much

more productive to find errors at compile time than to find them later

using a debugger.

While an application can use the new data types described above

without defining STRICT, it must use the new types if STRICT is

defined.

To enable STRICT type checking, an application must define the STRICT

environment variable before including WINDOWS.H, as follows:

   #define STRICT

   #include windows.h

The STRICT environment variable and the new data types are compatible

with Windows 3.0, C++, the Microsoft C Compiler's highest warning

level (specified by the -W4 option switch), and ANSI C.

An Example of Using STRICT

--------------------------

The ReleaseDC function is prototyped as follows:

   int WINAPI ReleaseDC(HWND, HDC);

In an application, a programmer might mistakenly switch the two

parameters to the ReleaseDC function, as follows:

   ReleaseDC(hDC, hWnd);

Traditionally, the compiler will not catch this error because both the

HDC and HWND data types are defined to be UINT variables. However, if

STRICT is enabled, the HDC and HWND data types are defined as

completely different types, which enables the compiler to catch the

error at compile time. (For more information about how the HWND and

HDC data types are defined, see the DECLARE_HANDLE macro in

WINDOWS.H.)

The WINDOWS.TXT file contains step-by-step instructions for writing

STRICT-compliant Windows code. WINDOWS.TXT also lists the most common

compiler errors generated while compiling an application with STRICT

defined, and methods to address these errors.

Converting Existing Code to STRICT

----------------------------------

WINDOWS.TXT describes how to convert existing Windows code to be

compatible with STRICT. However, this conversion requires a fair

amount of effort. If the existing code is stable and not modified very

often, the effort to convert the code may not be worthwhile.

Macros

------

The macros are implemented in WINDOWSX.H. Each one is listed and

described in WINDOWSX.TXT.

The macros can be used to simplify many common Windows programming

operations. Macros are designed to make code easier to read and write.

They can eliminate much typing and prevent type casting errors. The

macros are compatible with 32-bit Windows.

As an example, the traditional method to subclass a window involves

code such as the following:

   lpfnOldWndProc = SetWindowLong(hwnd, GWL_WNDPROC,

                                  (LPARAM)(WNDPROC)lpfnNewWndProc);

The following code, which uses a new macro, accomplishes the same

task:

   lpfnOldWndProc = SubclassWindow(hwnd, lpfnNewWndProc);

Other macros include: GlobalAllocPtr, DeletePen, SelectBitmap, and

GetWindowID.

Control Message Macros

----------------------

The control message macros are implemented in WINDOWSX.H. Each one is

listed and described in WINDOWSX.TXT.

The control message macros simplify dealing with Windows controls

(edit controls, list boxes, and so forth). Using the control message

macros makes code smaller, potentially more readable, and handles all

type casting required. When used in conjunction with the STRICT

preprocessor variable, the control message functions prevent type

errors and incorrect parameter passing.

Examples of control message macros are: Static_Enable,

Button_GetCheck, Edit_GetLineCount, and ScrollBar_SetRange.

Each control message macro corresponds to an existing control message

or window manager function. For example, Button_GetCheck can be used

in place of the BM_GETCHECK message and Button_SetText can be used in

place of SetWindowText.

A Control Message Macro Example

-------------------------------

The following example illustrates the power of the control message

macros.

The following code uses traditional SendMessage calls to retrieve all

the lines of text from an edit control:

   void PrintLines(HWND hwndEdit)

   {

      int line;

      int lineLast = (int)SendMessage(hwndEdit, EM_GETLINECOUNT,

                                      0, 0L);

      for (line = 0; line < lineLast; line)

      {

         int cch;

         char ach[80];

         *((LPINT)ach) = sizeof(ach);

         cch = (int)SendMessage(hwndEdit, EM_GETLINE,

                                line, (LONG)(LPSTR)ach);

         printf(ach); // or whatever ...

      }

   }

The following code uses control message macros to perform the same

task, retrieving all the lines of text from an edit control:

   void PrintLines(HWND hwndEdit)

   {

      int line;

      int lineLast = Edit_GetLineCount(hwndEdit);

      for (line = 0; line < lineLast; line++)

      {

         int cch;

         char ach[80];

         cch = Edit_GetLine(hwndEdit, line, ach, sizeof(ach));

         printf(ach); // or whatever ...

      }

   }

Message Crackers

----------------

The message crackers are implemented in WINDOWSX.H. The message

crackers are described in WINDOWSX.TXT, which also explains in some

detail how to use them. WINDOWSX.TXT does not list all message

crackers; the list is available in WINDOWSX.H.

The two biggest advantages to using message crackers are:

 - Data type safety, because the message crackers perform a great deal

   of type casting

 - Simplified porting to 32-bit Windows

An application can use message crackers whether or not it defines

STRICT. Also, an application can use message crackers to process some

messages and traditional code to process others.

Using message crackers radically alters the appearance of a window

procedure (see the example below). Whether or not this change of

appearance is a desirable side effect depends on the coding tastes of

the application developer.

Typically, a window procedure will handle many messages, with code in

the procedure to process each message. This often leads to the source

code for a window procedure continuing on for many pages. When an

application uses message crackers, almost any window procedure can be

listed very concisely. The bulk of the code is transferred to message-

handling functions that the message crackers call.

A Simple Message Cracker Example

--------------------------------

The following code sample demonstrates using the HANDLE_WM_* message

crackers in a window procedure:

   LRESULT _export CALLBACK Template_WndProc(HWND hwnd, WORD msg,

                                             WPARAM wParam,

                                             LPARAM lParam)

   {

      switch (msg)

      {

      case WM_MOUSEMOVE:

         return HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam,

                                    Template_OnMouseMove);

      case WM_LBUTTONDOWN:

         return HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam,

                                      Template_OnLButtonDown);

      case WM_LBUTTONUP:

         return HANDLE_WM_LBUTTONDUP(hwnd, wParam, lParam,

                                     Template_OnLButtonUp);

      case WM_CTLCOLOR:

         return HANDLE_WM_CTLCOLOR(hwnd, wParam, lParam,

                                   Template_OnCtlColor);

      default:

         return Template_DefProc(hwnd, msg, wParam, lParam);

      }

   }

The application must also contain the following message-handling

functions that are called by the message crackers:

   void Template_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)

   {

      // code to handle WM_MOUSEMOVE...

   }

   void Template_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x,

                               int y, UINT keyFlags)

   {

      // code to handle WM_LBUTTONDOWN...

   }

   void Template_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)

   {

      // code to handle WM_LBUTTONUP

   }

   HBRUSH Template_OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild,

                              int type)

   {

      // code to handle WM_CTLCOLOR

   }

While the window procedure code given above is compact, the HANDLE_MSG

macro simplifies the code even further. For example:

   LRESULT _export CALLBACK Template_WndProc(HWND hwnd, WORD msg,

                                             WPARAM wParam,

                                             LPARAM lParam)

   {

       switch (msg)

       {

       HANDLE_MSG(hwnd, WM_MOUSEMOVE, Template_OnMouseMove);

       HANDLE_MSG(hwnd, WM_LBUTTONDOWN, Template_OnLButtonDown);

       HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, Template_OnLButtonDown);

       HANDLE_MSG(hwnd, WM_LBUTTONUP, Template_OnLButtonUp);

       default:

           return Template_DefProc(hwnd, msg, wParam, lParam);

       }

   }

Message Cracker Basics

----------------------

If a window procedure uses a message cracker to process a particular

message, it must also implement a function to process that message.

This function must have a specific "signature" (the order and types of

parameters and the function's return type). The correct signature for

each function is listed in WINDOWSX.H next to the corresponding

message cracker.

For example, if the window procedure in the example above uses the

HANDLE_WM_MOUSEMOVE message cracker, it must also implement the

Template_OnMouseMove function, which the message cracker calls.

Once the application implements Template_OnMouseMove, the message

cracker processes the message as follows:

1. Splits wParam and lParam into component parts

2. Type casts the parts correctly

3. Passes the values as parameters to the application-supplied

   function (in this case, the Template_OnMouseMove function)

4. Returns an appropriate value from processing the message

For more information on the inner workings of the message crackers,

see the section titled "How Message Crackers Work" in WINDOWSX.TXT.

Message Crackers Have Many Uses

-------------------------------

The WINDOWSX.TXT text file explains and illustrates how to use message

crackers in many different application programming situations,

including the following:

 - Passing messages to DefWindowProc, CallWindowProc, and so forth.

 - Private and registered window messages.

 - Windows with instance data.

 - Dialog box procedures.

 - Window subclassing.

 - Another way to create dialog box procedures that allows a dialog

   box procedure to return an LRESULT data type. This method allows an

   application to bypass the traditional limitation that dialog box

   procedures must return a BOOL data type.

Additional reference words: 3.10

KBCategory: kbprg kbcode

KBSubcategory: TlsMisc


PRB: Binding Resources to Executable Increases File Size

Article ID: Q83917

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

Using the Resource Compiler (RC) to bind resources to a Windows

executable image file [either an application EXE file or a dynamic-

link library (DLL) file], the size of the output file is much

larger than the combined sizes of the input files.

CAUSE

=====

The Resource Compiler uses the same byte alignment as the linker.

By default, the Microsoft Linker aligns segments on a 512-byte

boundary.

RESOLUTION

==========

Use a linker option to specify a smaller byte alignment; specifying

a 16-byte boundary is recommended. With the Microsoft Linker, use

the /ALIGN:16 command-line switch.

MORE INFORMATION

================

The resource compiler uses the same byte alignment as the linker to

minimize the time to load the segments of an application. However,

one-half the byte alignment is wasted for each code segment and

resource on average. When an application has a number of small

resources, like a string table, specifying a large alignment value

leads to a large amount of wasted space in the file. Linking the

application with a smaller byte alignment eliminates most of the

wasted space.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsRc


SPY Utility Reports Application Name, Not Module Name

Article ID: Q84481

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

When the SPY utility provided with the Microsoft Windows Software

Development Kit (SDK) reports the module name for a running

application, it reports the name of the executable file. However, the

module name and the name of the application don't need to match. The

module name of an application is specified in the NAME statement in

the application's module definition (DEF) file.

For example, SPY indicates that the module name for Microsoft Word for

Windows is WINWORD. However, calling GetModuleHandle("WINWORD") always

returns zero even when Word for Windows is running.

The EXEHDR utility, which is also provided with the Windows SDK,

reports the correct module name for an application. EXEHDR reports the

module name for Word for Windows as MSWORD. GetModuleHandle("MSWORD")

returns the module handle for Word for Windows if it is running.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsSpy


PRB: Borland Turbo Debugger Cannot Load WINDEBUG.DLL

Article ID: Q84844

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

An attempt to run the Borland Turbo Debugger under Windows 3.1

generates a message stating that the WINDEBUG.DLL file is not found.

CAUSE

=====

The Borland Turbo Debugger requires the WINDEBUG.DLL file to work with

the Windows environment.

RESOLUTION

==========

WINDBG is a file in the Software Library that contains the

WINDEBUG.DLL. WINDBG is for registered owners of Borland language

products that require the file to run the Borland Turbo Debugger under

Windows 3.1. WINDBG may not be redistributed in any way.

Download WINDBG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINDBG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINDBG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get WINDBG.EXE

Additional reference words: 3.10

KBCategory: kbtool kbprg kbfile kbprb

KBSubcategory: TlsMisc


Use Extended Memory to Build Larger Windows Help Files

Article ID: Q84931

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

A version of the Windows 3.1 Help Compiler which has been enhanced to use

extended memory is now available in the Microsoft Software Library. The

extended memory version of the Windows 3.1 Help Compiler (HCP.EXE)

generates files for the Windows 3.1 Help application. As with all previous

versions of the Windows Help Compiler, the new version runs under MS-DOS.

However, the new version requires extended memory and is best run in an MS-

DOS session under Windows.

Download HC505.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download HC505.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HC505.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HC505.EXE

The size and complexity of the files processed by earlier versions of the

Windows Help Compiler is constrained by the amount of free MS-DOS memory

available at compile time. This capacity constraint has caused difficulties

for some developers creating very large files for Windows Help. The HCP.EXE

application removes this capacity constraint.

For more information on the Windows Help Compiler, see Chapter 3 of the

"Microsoft Windows Software Development Kit: Programming Tools" for version

3.1 manual.

Additional reference words: 3.10 update new newest latest updated softlib

HC505.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsHlp


Application Cannot Clear the Windows Help History List

Article ID: Q85594

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

In the Windows 3.1 Help application, when the user chooses the History

button on the button bar, Windows Help displays a list of the previous

40 topics accessed.

If the user closes the Windows Help application and launches it again,

Windows Help creates a new history list. However, if one application

launches the Windows Help application and another application calls

Windows Help to display a different help file, the history list can

contain topics from each help file. This allows the user to move back

and forth between help files.

Windows Help version 3.1 does not provide a method to empty the

history list and remove references to any prior help files.

Additional reference words: 3.10 WinHelp HC HC.EXE HC31.EXE HCP.EXE

KBCategory: kbtool

KBSubcategory: TlsHlp


Setup Toolkit for Windows Compatible with Windows 3.0

Article ID: Q85597

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The "Microsoft Windows Software Development Kit: Setup Toolkit for

Windows," distributed with the Microsoft Windows Software Development

Kit (SDK) version 3.1, can create a setup script that is compatible

with Windows 3.0.

In addition to the six Microsoft setup dynamic-link libraries (DLLs),

the data decompression library (LZEXPAND.DLL) and the file

installation library (VER.DLL) must be included with the distribution

for the setup script to function properly.

Because LZEXPAND and VER are compatible only with protected mode,

these files cannot be used under real mode Windows version 3.0.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsMss


Windows Help and Help Compiler Capacity Limits

Article ID: Q85676

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following lists the limits of the Windows Help application, version

3.1. These limits are subject to change in future versions.

Paragraph size(1): approximately 32,000 bytes

Topic title string length: 127 characters

Topics per RTF source file: approximately 32,700

Topics per help file: 42,000,000

By-reference bitmaps per help file : 32,767

Help file size: approximately 2,157,000,000 bytes (2 gigabytes)

Topic footnote character limit: 1023 characters

Keywords per help file: limited only by file size

Keyword length: 255 bytes

Topics per keyword(2): 32,767

Browse sequence length: limited only by the number of topics

Bookmarks per help file: limited only by file size

Annotations per topic: 1

Annotations per help file: 32,767

History list length: 40 topics

Text that can be copied to clipboard: limited only by machine memory

Macro length: 512 characters

Main windows per topic: 1

Secondary windows per topic: 5

(1) The maximum paragraph size includes graphics pasted into the RTF

source. Therefore, each pasted graphic is limited to 32,000 bytes. To

work around this limitation, import large bitmaps by reference.

(2) Performance degrades for files with more than several hundred

topics. The Search dialog box displays a maximum of 400 topics.

Additional reference words: 3.10 HC HCP.EXE HC31.EXE WinHelp

KBCategory: kbtool

KBSubcategory: TlsHlp


Sources of Information about the Windows Help Compiler

Article ID: Q85677

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Windows Software Development Kit (SDK) has much

information about the Windows Help Compiler and Windows Help

application. This article lists the various sources of information

about Windows Help available in the SDK.

MORE INFORMATION

================

 - The "Microsoft Windows Software Development Kit: Programmer's

   Reference, Volume 2: Functions" manual documents the WinHelp

   function on pages 985 through 988.

 - The "Microsoft Windows Software Development Kit: Programming Tools"

   manual, in Chapter 3, presents an overview of the process of

   creating a help file. A list of error messages with a description

   of each appears in Appendix B.

 - The "Microsoft Windows Software Development Kit: Programmer's

   Reference, Volume 4: Resources" manual, pages 257 through 302,

   lists the RTF (rich-text format) tokens supported by the Windows

   Help Compiler. Pages 302 through 330 list the syntax of each macro

   supported by the Help Compiler and provides a description of each.

 - The HELPHOOK sample demonstrates how an application can provide

   context-sensitive help for a dialog box. HELPHOOK is one of the

   advanced samples provided with the Windows SDK. By default, the

   SDK installation program places advanced samples in the

   C:\WINDEV\SAMPLES directory.

 - The HELPEX sample demonstrates calling Windows Help from an

   application and provides a general demonstration of its

   capabilities. HELPEX is one of the advanced samples provided with

   the Windows SDK.

 - The MACROHLP sample demonstrates many of the macros available to

   Windows Help authors. MACROHLP is one of the advanced samples

   provided with the Windows SDK.

Additional reference words: 3.10 HC HCP.EXE HC31.EXE

KBCategory: kbtool

KBSubcategory: TlsHlp


PRB: "Unrecognized Linker Switch /NOP" Linking Setup Toolkit

Article ID: Q85889

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Building the Setup Toolkit for Windows provided with version 3.1 of the

Microsoft Windows Software Development Kit (SDK) causes the following error

message when the application is linked:

   LINK: Fatal error L1001: NOP : option name ambiguous

   -or-

   Unrecognized Linker Switch /NOP

CAUSE

=====

The Setup Toolkit is built with the Microsoft C/C++ compiler version 7.0.

The Setup Toolkit files are designed for use with Microsoft C version 6.0.

RESOLUTION

==========

Modify the CUISTF.LNK and CUISTFD.LNK files in the Setup Toolkit BLDCUI

directory (by default, C:\WINDEV\MSSETUP\BLDCUI) to replace the /NOP switch

in the first line with the /NOPACKC switch. The first line of the corrected

files is as follows:

   /NOL /NOPACKC /align:16 libentry dlgprocs

Additional reference words: 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMss


WDEB386-Compatible Timing Card Available

Article ID: Q85897

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

The Microsoft Windows 80386 Debugger (WDEB386.EXE) is documented in Chapter

5 of the "Microsoft Windows Software Development Kit: Programming Tools"

manual. The documentation for the gs and gh commands, on page 148,

indicates that each of these commands requires a timing card.

One timing card compatible with WDEB386 is the STAT! System Timing Analysis

Tool, manufactured by Alpha Logic Technologies, Inc. For more information

regarding this product, contact Alpha Logic Technologies at (206) 644-3094.

The product included here is manufactured by a vendor independent of

Microsoft; we make no warranty, implied or otherwise, regarding this

product's performance or reliability.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsWdeb


Porting Windows Help Source Files from Version 3.0 to 3.1

Article ID: Q86080

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

To successfully compile source files developed for version 3.0 of the

Microsoft Windows Help Compiler with version 3.1 of the Help Compiler,

make the following two changes to the Help Project (HPJ) file:

 - In the [OPTIONS] section, replace the INDEX statement with the

   CONTENTS statement. The CONTENTS statement provides the same

   functionality; it specifies the context string of the highest-level

   topic. This topic is usually a table of contents or an index of the

   help file. The Windows Help application displays the contents topic

   whenever the user chooses the Contents button. The syntax of the

   CONTENTS statement is as follows:

      [OPTIONS]

      CONTENTS=context-string

 - If the Help file contains any browse sequences, add the browse

   buttons to the button bar with the following statement in the

   [CONFIG] section:

      [CONFIG]

      BrowseButtons()

   Version 3.1 of the Windows Help Compiler does not display the

   browse buttons by default. For more information on browse buttons,

   see page 28 of the "Programming Tools" manual included with the

   Microsoft Windows Software Development Kit (SDK) version 3.1.

Because version 3.1 of the Windows Help Compiler cannot produce

backwardly compatible help files, the files it creates are

incompatible with version 3.0 of Windows Help. However, Windows Help

version 3.1 will run under Microsoft Windows 3.0 and is

redistributable. See the License Agreement for the Microsoft Windows

SDK version 3.1 for information about reproducing and distributing

WINHELP.EXE with your product.

Additional reference words: 3.00 3.10 HC31 HC31.EXE HCP HCP.EXE

KBCategory: kbtool

KBSubcategory: TlsHlp


Windows Help Print Macro Does Not Print Pop-up Contents

Article ID: Q86261

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

The author of a file for the Microsoft Windows Help application can use the

Print macro to print the contents of the current topic.

In Windows Help version 3.1, it is not possible to include the contents of

an active pop-up window in the printed output. Executing the Print macro in

a pop-up window prints only the contents of the topic that created the pop

up.

Additional reference words: 3.10 WinHelp HC31 HC31.EXE HCP HCP31.EXE

KBCategory: kbtool

KBSubcategory: TlsHlp


Cannot Destroy Default Windows Help Menus and Buttons

Article ID: Q86264

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

A help file built for version 3.1 of the Microsoft Windows Help

application can extend the Windows Help application via a number of

built-in macro commands. These macros allow the help file author to

create a new menu item or button and to delete an added item once it

is no longer needed.

However, one cannot use the DeleteItem and DestroyButton macros to

remove a standard menu item from the Windows Help application's menus

or to remove a button from the standard button bar.

The standard menu items are fixed by the Windows Help application;

however, one can modify the behavior of the standard buttons via the

ChangeButtonBinding macro.

For more information on Windows Help macros, see Section 15.4

(starting on page 302) of the "Microsoft Windows Software Development

Kit: Programmer's Reference, Volume 4: Resources" manual or the

MACROHLP application provided with the Microsoft Windows Software

Development Kit (SDK) in the advanced samples directory (by default,

C:\WINDEV\SAMPLES).

Additional reference words: 3.10 WinHelp Compiler HC31 HC31.EXE HCP

HCP.EXE

KBCategory: kbprg

KBSubcategory: TlsHlp


PRB: Bitmap Causes Windows Help Compiler Out-of-Memory Error

Article ID: Q86332

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When version 3.1 of the Microsoft Windows Help Compiler compiles an

RTF (rich-text format) file, the compiler runs out of memory. This

occurs in the HC31.EXE application running under MS-DOS or OS/2 and

in the HCP.EXE application that uses extended memory under MS-DOS.

CAUSE

=====

The RTF file contains a pasted bitmap larger than 64K.

RESOLUTION

==========

Remove the bitmap from the RTF source and store it in a file.

Import the bitmap into the RTF source file by reference. For more

information on importing a bitmap by reference, see page 29 of the

"Microsoft Windows Software Development Kit: Programming Tools"

manual, and pages 258-260 of the "Microsoft Windows Software

Development Kit: Programmer's Reference, Volume 4: Resources"

manual.

This problem does not occur with help compiler version 4.0 (HCW.EXE).

Additional reference words: 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


Using LINK 5.3 to Create Applications for Real Mode

Article ID: Q86922

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The Microsoft C/C++ Optimizing Compiler version 7.0 includes the Microsoft

Segmented Executable Linker (LINK) version 5.3. By default, when LINK

version 5.3 links an application for Microsoft Windows, the executable file

is compatible only with protected mode.

To override this default, specify the REALMODE directive in the

application's module definition (DEF) file. Note that Windows 3.1 no longer

supports real mode applications.

The REALMODE directive is documented on page 617 of the "Microsoft C/C++

Environment and Tools" version 7.0 manual.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: TlsMisc


PRB: Building Setup Toolkit Overwrites DIALOGS.RES File

Article ID: Q87008

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the Resource Compiler builds the resources for the custom DLL in the

Setup Toolkit provided with the Microsoft Windows Software Development Kit

(SDK) version 3.1, the DIALOGS.RES file is overwritten.

RESOLUTION

==========

Modify the files in the Setup Toolkit BLDCUI directory (by default,

C:\WINDEV\MSSETUP\BLDCUI) as follows:

1. In the DIALOGS.DLG file, add the following two statements:

      #include <windows.h>

      #include "dialogs.h"

2. Rename the DIALOGS.RC file to MSCUISTF.RC.

3. Edit MAKEFILE as follows:

   a. Find all occurrences of DIALOGS.RC and replace them with

      MSCUISTF.RC.

   b. Find all occurrences of DIALOGS.RES and replace them with

      MSCUISTF.RES.

MORE INFORMATION

================

It is necessary to make these changes before customizing the Setup

Toolkit dialog boxes with the Dialog Editor. If the dialog box

template, DIALOGS.RES, grows to larger than 64K, the Dialog Editor

cannot load the file. For information on rebuilding the dialog

template from the DIALOGS.DLG file, query in the Microsoft Knowledge

Base on the following words:

   dialog editor corrupt

Additional reference words: 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMss


Packing List: Windows 3.1 SDK Part 1 (3.5-Inch Disks)

Article ID: Q87114

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions  3.1

---------------------------------------------------------------------

SUMMARY

=======

The following is the packing list for the Microsoft Windows Software

Development Kit (SDK) version 3.1:

   Disk 1

   ------

   INSTALL.EXE    Setup program

   INSTALL.INF    Information file for Setup program

   README.SDK     SDK information not in online help

   ROBUST.TXT     Information about creating robust applications

   WINDOWS.TXT    Lists changes to WINDOWS.H since Windows 3.0

   WINDOWSX.TXT   Information on message crackers, WINDOWSX.H file

   README.WRI     SDK information not in online help

   VPROD.386      Virtual machine device driver

   HOOK.DLL       Hook DLL

   DDESPY.EXE     Displays DDE messages between applications

   HEAPWALK.EXE   Heap Walker application

   SHOWHITS.EXE   Displays data from Windows Profiler

   SPY.EXE        Displays messages between applications

   STRESS.EXE     Resource limiting utility

   STRESS.HLP     Resource limiting utility help file

   STRESS.INI     Resource limiting utility initialization file

   COMPRESS.EXE   File compression utility

   MARK.EXE       Marks files with memory and font info

   GDI.SYM        GDI nondebugging symbol file

   KRNL286.SYM    Kernel 286 nondebugging symbol file

   KRNL386.SYM    Kernel 386 nondebugging symbol file

   MMSYSTEM.SYM   Multimedia nondebugging symbol file

   USER.SYM       Windows user nondebugging symbol file

   VER.DLL        Version checking redistributable DLL

   SMALLF.FON     8514 small font for Windows

   HC.BAT         Help Compiler batch file

   DBWIN.DLL      Debugging DLL

   HC31.ERR       Help Compiler version 3.1 error file

   RCPP.ERR       Resource Compiler preprocessor error file

   DBWIN.EXE      Debugger

   DLGEDIT.EXE    Dialog Editor

   FONTEDIT.EXE   Font Editor

   HC30.EXE       Help Compiler version 3.0

   HC31.EXE       Help Compiler version 3.1

   IMAGEDIT.EXE   Image Editor

   MARKMIDI.EXE   MIDI file marker

   MRBC.EXE       Multiple Resolution Bitmap Compiler

   QH.EXE         Quick Help utility

   RC.EXE         Resource Compiler

   RCPP.EXE       Resource Compiler preprocessor

   SHED.EXE       Segmented Hypergraphics (hotspot) Editor

   ZOOMIN.EXE     Zoom utility

   ATRM1111.FNT   Sample font file

   VGASYS.FNT     VGA font file

   SDKTOOL1.GRP   Temporary group file for setup

   SDKTOOLS.GRP   Windows SDK group file

   DLGEDIT.HLP    Dialog Editor help file

   EDITHLP.HLP    Help on Help file

   IMAGEDIT.HLP   Image Editor help file

   QH.HLP         Quick Help help file

   SHED.HLP       Segmented Hypergraphics Editor help file

   MAKEFILE       SRVRDEMO sample application project file

   DOC.C          SRVRDEMO sample application source file

   FILE.C         SRVRDEMO sample application source file

   INI.REG        Registration initialization file

   WINSTUB.EXE    STUB file for Windows applications

   Disk 2

   ------

   CVW3.EXE       CodeView for Windows version 3.07

   CVW3.HLP       CodeView for Windows 3.07 help file

   CVWIN.DLL      CodeView for Windows DLL

   D2N.BAT        Debugging Windows to nondebugging Windows batch file

   MAPSYM.EXE     Symbol file generator

   N2D.BAT        Nondebugging Windows to debugging Windows batch file

   SWITCH.BAT     Performs debugging-nondebugging conversion

   VCV.386        Video driver for CodeView for Windows

   WDEB386.EXE    Low level debugger

   WINDEBUG.386   Low level debugger device driver

   GDI.EXE        Debugging version of GDI

   GDI.SYM        Symbol table for debugging GDI

   KRNL286.EXE    Debugging version of kernel 286

   KRNL286.SYM    Debugging kernel 286 symbol table

   KRNL386.EXE    Debugging version of kernel 386

   KRNL386.SYM    Debugging kernel 386 symbol table

   MMSYSTEM.DLL   Debugging version of multimedia DLL

   MMSYSTEM.SYM   Debugging multimedia DLL symbols table

   USER.EXE       Debugging version of user

   USER.SYM       Debugging user symbol table

   RAINBOW.C      RAINBOW sample program

   Disk 3

   ------

   STRESS.DLL     Resource limiting DLL

   STRESSHK.DLL   Resource limiting DLL component

   STRESSLG.DLL   Resource limiting DLL component

   CDERR.H        Common dialog box DLL error codes

   CMACROS.INC    Assembly language macros for Windows

   COLORDLG.H     Common dialog box DLL color ID numbers

   COMMDLG.H      Common dialog box DLL header file

   CPL.H          Control Panel DLL extensions

   CUSTCNTL.H     Custom control library header file

   DDE.H          Dynamic data exchange header file

   DDEML.H        Dynamic Data Exchange Management Library header file

   DLGS.H         Common dialog box DLL member ID numbers

   DRIVINIT.H     Obsolete header file

   LZDOS.H        Obsolete header file

   LZEXPAND.H     Data decompression DLL header file

   MMSYSTEM.H     Multimedia header file

   MMSYSTEM.INC   Multimedia header file for assembly language

   OLE.H          Object linking and embedding header file

   PENWIN.H       Pen Windows functions header file

   PENWOEM.H      Pen Windows Recognizer function header file

   PRINT.H        Printing helper functions header file

   SCRNSAVE.H     Screen saver header file

   SHELLAPI.H     Shell DLL header file

   STRESS.H       Resource limiting test DLL header file

   TOOLHELP.H     Tool Helper DLL header file

   TOOLHELP.INC   Tool Helper DLL header file for assembly language

   VER.H          Version checking DLL header file

   WFEXT.H        File Manager extensions header file

   WINDOWS.H      Windows functions header file

   WINDOWSX.H     Message cracker header file

   WINMEM32.H     Windows 32-bit API header file

   COMMDLG.DAN    Common dialogs DLL Danish

   COMMDLG.DLL    Common dialogs DLL US

   COMMDLG.DUT    Common dialogs DLL Dutch

   COMMDLG.FIN    Common dialogs DLL Finnish

   COMMDLG.FRN    Common dialogs DLL French

   COMMDLG.GER    Common dialogs DLL German

   COMMDLG.ITN    Common dialogs DLL Italian

   COMMDLG.NOR    Common dialogs DLL Norwegian

   COMMDLG.POR    Common dialogs DLL Portuguese

   COMMDLG.SPA    Common dialogs DLL Spanish

   COMMDLG.SWE    Common dialogs DLL Swedish

   DDEML.DLL      Dynamic Data Exchange Management Library

   DIB.DRV        Device independent bitmap driver

   EXPAND.EXE     File decompression utility

   LZEXPAND.EXE   Data decompression utility

   MCIPIONR.DRV   Laser disk device driver

   OEMSETUP.INF   Media Control Interface setup information file

   OLECLI.DLL     Object linking and embedding client DLL

   OLESVR.DLL     Object linking and embedding server DLL

   PENWIN.DLL     Windows for Pen Computing DLL

   REGLOAD.EXE    Registration file loader

   SMALLB.FON     VGA small font for Windows

   SMALLE.FON     EGA small font for Windows

   TOOLHELP.DLL   Tool Helper DLL

   VTD.386        Virtual timing device driver

   WINHELP.EXE    Windows Help application

   WINMEM32.DLL   32-bit memory API DLL

   RAINBOW.DLL    Custom control DLL

   MAKEFILE       Sample project file

   COMMDLG.LIB    Common dialog box static Library

   DDEML.LIB      Dynamic Data Exchange Management Library (static)

   LIBENTRY.ASM   DLL entry source code

   LIBENTRY.OBJ   DLL entry object code

   LIBW.LIB       Windows API library

   LZEXPAND.LIB   Data decompression static library

   LZEXPC.LIB     Data decompression library compact model extensions

   LZEXPL.LIB     Data decompression library large model extensions

   LZEXPM.LIB     Data decompression library medium model extensions

   LZEXPS.LIB     Data decompression library small model extensions

   MMSYSTEM.LIB   Multimedia API static library

   OLECLI.LIB     Object linking and embedding client static library

   OLESVR.LIB     Object linking and embedding server static library

   PENWIN.LIB     Windows for Pen Computing static library

   SCRNSAVE.LIB   Screen saver extensions static library

   SHELL.LIB      Shell static library

   STRESS.LIB     Resource limiting DLL static library

   TOOLHELP.LIB   Tool Helper static library

   VER.LIB        Version checking DLL static library

   VERC.LIB       Version checking DLL compact model extension

   VERL.LIB       Version checking DLL large model extension

   VERM.LIB       Version checking DLL medium model extension

   VERS.LIB       Version checking DLL small model extension

   WIN87EM.LIB    Coprocessor library

   WINMEM32.LIB   Windows 32-bit API static library

Additional reference words: 3.10

KBCategory: kbref kbsetup

KBSubcategory: TlsFls


PRB: Small Caps Text Unchanged in Windows Help

Article ID: Q87342

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When a help file developed for version 3.1 of Microsoft Windows

Help contains non-alphabetic characters formatted with the Small

Caps character formatting, the Microsoft Windows Help application

displays these characters at normal size.

RESOLUTION

==========

To work around this limitation, change the case of the characters.

The following macro for version 2.0 of Microsoft Word for Windows

performs this conversion:

   Sub MAIN

   StartOfDocument

   EditFindChar .Font = "", .Points = "", .Bold = - 1, \

   .Italic = - 1, .Strikeout = - 1, .Hidden = - 1, .SmallCaps = 1, \

   .AllCaps = 0, .Underline = - 1, .Color = - 1, .Position = "", \

   .Spacing = ""

   EditFind .Find = "", .WholeWord = 0, .MatchCase = 0, \

   .Direction = 1, .Format = 1

   While EditFindFound()

        Size = FontSize()

        Size = Size - 2

        FontSize Size

        SmallCaps 0

        ChangeCase 1

        EditFind .Find = "", .WholeWord = 0, .MatchCase = 0, \

        .Direction = 1, .Format = 1

   Wend

   End Sub

MORE INFORMATION

================

Although you can still use this help compiler with Windows NT 3.51 and

Windows 95, there is a new help compiler 4.0 (HCW.EXE), which should be

used instead of the older help compiler.

Additional reference words: 3.10 HC31 HC31.EXE HCP HCP.EXE RTF /scaps

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


Using the Microsoft Windows Help Compiler

Article ID: Q88191

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Although Section 2.1.11 of the Microsoft Windows Software Development

Kit (SDK) "Getting Started" manual for version 3.1 briefly mentions

the Microsoft Windows Help Compiler, it gives no information about how

to use it.

The Windows SDK "Programming Tools" manual for version 3.1 documents

how to create a Windows Help file in Chapter 3. However, it does not

detail how to invoke the Help Compiler. The text below explains how to

use the Help Compiler and some of the differences between the two

versions of the Help Compiler provided with version 3.1 of the Windows

SDK.

MORE INFORMATION

================

The Windows SDK documentation details how to create the source files

required to build a Windows Help file. The Help Compiler creates an

.HLP file from the source files. Version 3.1 of the Windows SDK

includes two versions of the Help Compiler: one (HC30.EXE) builds .HLP

files compatible with the version 3.0 of the Windows Help application,

and the other (HC31.EXE) builds files compatible only with Windows

Help version 3.1. A batch file (HC.BAT) provides compatibility with

the HC.EXE program in version 3.0 of the Windows SDK. The batch file

can invoke either version of the Help Compiler.

The source files used to create a Windows Help file include the Help

project (.HPJ) file, rich text (.RTF) files, bitmap (.BMP) files, and

segmented-graphic bitmap (.SHG) files. One of the parameters of the

Help Compiler command line is the name of the .HPJ file; the .HPJ file

lists the other source files.

Both compilers are MS-DOS-based (non-Windows) programs run from an

MS-DOS prompt or in an MS-DOS window under Windows. The Help Compiler

file (and its associated .ERR file) must be in a directory listed in

the MS-DOS PATH environment variable (in the AUTOEXEC.BAT file) or in

the current directory. The Windows SDK installation program places

both compilers and the batch file in the Windows SDK BIN directory (by

default, either C:\WINDEV\BIN or C:\C700\BIN).

The HC.BAT batch file invokes the Help Compiler application. By

default, HC.BAT invokes HC30.EXE to build a Help file compatible with

version 3.0 of the Windows Help application. HC30 does not support

some features of Windows Help version 3.1 (such as segmented-graphic

bitmaps). To create a Help file for Windows Help version 3.1, either

invoke HC.BAT with the -n option switch (for example, hc -n

myhelp.hpj) or invoke HC31.EXE directly (for example, hc31

myhelp.hpj).

Section 2.1.11 of the "Getting Started" manual (page 10) lists some of

the new features provided by Windows Help version 3.1.

NOTE: You can still use this help compiler with Windows NT 3.51 and Windows

95, but there is a new help compiler 4.0 (HCW.EXE) which should be used for

these platforms instead of the old help compiler.

Additional reference words: 3.00 3.10 HC HC.BAT HC30 HC31 hypergraphic

KBCategory: kbtool

KBSubcategory: TlsHlp


How to Maximize Setup Toolkit Window

Article ID: Q88414

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

The Microsoft Setup Toolkit for Windows does not provide any options

or functions for maximizing the frame window. The frame window will

always be initially displayed as an unmaximized window with a caption.

However, you can call the Windows ShowWindow and SetWindowLong

application programming interface (API) functions from a script to

maximize the frame and remove the caption. If the calls are made at

the beginning of the script, there will be only a quick flicker as the

window size and border are changed. The following code can be used to

do this:

''following were taken from windows.h. &H means they're hex

CONST WS_VISIBLE=&H10000000

CONST WS_BORDER =&H00800000

CONST WS_CLIPCHILDREN =&H02000000

CONST GWL_STYLE =-16

CONST SW_SHOWMAXIMIZED=3

DECLARE FUNCTION ShowWindow  LIB "user.exe" (hWnd%,iShow%) AS INTEGER

DECLARE FUNCTION SetWindowLong LIB "user.exe" (hWnd%, offset%, style&)

                AS LONG     ''this declaration must all be on one line

.

.

.

hWnd%=HwndFrame()

i1&=SetWindowLong(hWnd%,GWL_STYLE,WS_VISIBLE+WS_BORDER+WS_CLIPCHILDREN)

j1%=ShowWindow(hWnd%,SW_SHOWMAXIMIZED)

.

.

.

Additional reference words:  3.10 MSSetup tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


Details of Setup Toolkit Function GetCopyListCost()

Article ID: Q88749

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version

   3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Setup Toolkit for Windows GetCopyListCost() function can

be used to compute the cost needed to install the files in the copy

list to the target. The syntax for GetCopyListCost() is:

   Long&=GetCopyListCost(szExtras$,szCosts$,szNeededs$)

szExtras$ is an input parameter to GetCopyListCost(), and szCosts$ and

szNeededs$ are output parameters. All three parameters are symbols

whose values are lists of up to 26 integers. The nth integer in the

list will have the information about the nth alphabetic drive, where

the drives are A-Z.

If there will be extra costs beyond the cost of copying and

decompressing the files in the copy list, these costs should be

included in szExtras$. For example, to specify an extra cost of 5000

bytes on the Windows drive, the code might resemble the following:

   WinDrive$ = MID$(GetWindowsDir, 1, 1)

   ndrive% = ASC (ucase$(WinDrive$)) - ASC ("A")

   for i% = 1 to ndrive% step 1

       AddListItem "ExtraCosts", "0"

   next i%

   AddListItem "ExtraCosts", "5000"

   need& = GetCopyListCost ("ExtraCosts", "costs", "needs")

If there are no extra costs, "" can be passed for szExtras$.

On return, the value of szCosts$ will be a list of 26 integers, which

are the total costs for drives A-Z of copying the files in the copy

list and of the costs in szExtras$. The value of szNeededs$ will be a

list of 26 integers, which are the total costs for each drive--the

amount of free space on the drive. For any drive that will not be

affected by the extra costs or by copying the copy list, szNeededs$

will report 0.

MORE INFORMATION

================

In computing szCosts$ and szNeededs$, all files sizes, as well as the

costs in szExtras$, are rounded up to the nearest cluster. The

integers in the lists will always be some multiple of the cluster size

for the appropriate drive. The cluster sizes in bytes for various

disks are as follows:

   Single-sided floppy disk    512

   Double-sided floppy disk   1024

   PC/AT fixed disk           2048

   PC/XT fixed disk           4096

   Other fixed disks          8192 & 16384

The cost of each file on the copy list is calculated as follows. The

properties mentioned are from the file's property list in the .INF

file:

if the file does not exist at the install target

   if the source file has the REMOVE property

      file cost=0

   else

      file cost=size of source file

else // the file does exist at the install target

{

   if the source file has the REMOVE property

      file cost=-size of existing file at target

   else if the file has the NEVER overwrite property

      file cost=0

   else if the existing target file is read only and the source file

               has the UNPROTECTED overwrite property

      file cost=0

   else if the file has the OLDER overwrite property and

               the existing target file is newer

      file cost=0

   else if the file has the OLDER overwrite property and

           the existing target file is exactly the same (i.e. no copy)

      file cost=size of source file (for temporary copy used for

                                           language version check

   else // file will be copied

   {

      file cost=size of source file - size of existing target file

      if existing dest file is to be backed up (source file has

                 BACKUP property)

         file cost=file cost+size of existing target file

   }

}

Note that GetCopyListCost() computes the copy cost incorrectly for split

files that already exist at the target. It erroneously reports that

most of the space used by the file will be freed.

Additional reference words: 3.10 MSSETUP tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


The Microsoft Setup Toolkit for Windows -- A Tutorial

Article ID: Q89572

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The information below demonstrates the basic functionality of the

Microsoft Setup Toolkit for Windows that is included with version 3.1

of the Microsoft Windows Software Development Kit (SDK). The Setup

Toolkit is a collection of tools and programs designed to build a

"setup" disk, that is, a disk (or group of disks) that install one or

more files onto a client's computer system.

Because the Setup program itself is designed for the Microsoft Windows

graphical environment, the Toolkit is primarily aimed at building

installation disks for the Windows environment. Functions in the

Toolkit copy software and other data files to the target disk, add

groups and items to the Microsoft Windows Program Manager, and create

or modify initialization (.INI) files. This tutorial does not discuss

all of these features; it concentrates on using the setup disk layout

tools and on creating a "basic" setup disk.

This tutorial covers the following topics:

 - Selecting the files to install on the client's system

 - Including the required Toolkit files on the setup disks

 - Creating the required directory structure on the client's system

 - Controlling file compression

 - Using the Dsklayt and Dsklayt2 utilities in the Setup Toolkit

This tutorial, which uses the sample script file included with the

Toolkit (with minor modifications), is designed to provide an overview

of the capabilities of the Toolkit. Before applying the Toolkit to any

particular task, additional information and preparation is required.

This tutorial does not discuss the following tasks:

 - Modifying the dialog boxes in Setup.

 - Modifying the setup scripts (beyond the minimum changes required to

   accomplish the tutorial's objectives).

 - Using the Setup procedures. (Even though the tasks in this tutorial

   use Setup procedures, the tutorial does not discuss them in any

   detail.)

MORE INFORMATION

================

The Setup Toolkit contains three major component groups:

1. The disk layout utilities that create "setup" disks. A client uses

   the setup disks to install software onto a target system. The

   primary focus of this tutorial is these utilities and how to use

   them.

2. The setup tools required to install the software. Microsoft

   provides the setup tools in the SDK. The setup tools must be

   included on the setup disks. This tutorial discusses the setup

   tools only briefly.

3. Dialog boxes, sample setup scripts, and other files that control

   the appearance and operation of the Setup program. These factors

   are either ignored by this tutorial or are discussed at only the

   most basic level.

The Setup Toolkit directory (by default, C:\WINDEV\MSSETUP or

C:\C700\MSSETUP) contains two information files in Microsoft Windows

Write format: README.WRI and FILEDESC.WRI. These files provide a great

deal of reference information.

As outlined in the "Setup Toolkit for Windows" manual provided with

the Windows SDK, using the Setup Toolkit involves seven steps, as

follows:

1. Identify the files to install.

2. Design a directory structure for those files.

3. Identify all user-defined parameters.

4. Design the required dialog boxes.

5. Modify the sample script files.

6. Create images of the installation disks.

7. Test the setup disks.

This tutorial concentrates on steps 1, 2, and 6.

The remainder of this article is organized as follows:

 - Discuss steps 1 and 2 (identify files and directories)

 - Exercise 1: Create a directory of files to install

 - Briefly discuss steps 3, 4, and 5 (parameters, dialog boxes, script

   files)

 - Discuss step 6 (create disk images)

 - Exercise 2: Use the Dsklayt utility

 - Exercise 3: Modify the setup list file

 - Exercise 4: Modify the script file

 - Exercise 5: Use the Dsklayt2 utility

 - Exercise 6: Create and test the setup disks

Identify the Files to Install

-----------------------------

To build setup disks, it is necessary to determine the files to

install on the target system. This tutorial outlines the procedures to

install the Generic application, one of the sample applications

discussed in the Windows SDK "Guide to Programming" manual. Feel free

to substitute other files if Generic is not readily available. Under

normal circumstances, installing an application would not involve

installing source code (source code might be an optional item).

However, the steps outlined below install the source code to Generic

along with its executable file. The source files are listed below in

the discussion of directory structure.

NOTE: Make sure that you build the Generic executable before the first

exercise. For more information, see Chapter 1 of the "Guide to

Programming" manual.

In addition to the installed files, you must include some Setup

Toolkit files on the setup disks. The process marks these files to

prevent them from being installed on the client's system.

Design a Directory Structure

----------------------------

Given the list of files to install, determine where the files belong

on the client's system. As a practical matter, it helps to build the

directory structure and to copy the files into it. Then you can build

setup disks from these files. If disk space is very tight, you may not

be able to build the complete tree structure. In that case, remember

that the Dsklayt utility cannot change directories. Therefore, you

must start it in a directory that can access all the needed files,

including the Toolkit files. This tutorial discusses these

considerations in more detail below.

Exercise 1: Files and Directories

---------------------------------

This exercise uses the following directory structure:

   Root

    |

    +Generic

       |

       +Sources

In other words, the GENERIC directory is a child of the root and it

has a subdirectory named SOURCES. Copy all the files from the SDK

Guide samples GENERIC directory into the GENERIC\SOURCES directory.

Move GENERIC.EXE from the SOURCES directory to the GENERIC directory.

Copy the following files from the SDK Setup Toolkit directory into the

GENERIC directory: all .EXE files, all .DLL files, all .INC files,

SAMPLE1.MST, and SETUP.LST. The files marked with "<<<" in the list

below are not required for all installations. The FILEDESC.WRI file

details when these files are needed. Although it is always safe to

include these files, they consume space on the setup disks.

If you create the GENERIC directory from the root of the C drive, the

MS-DOS TREE utility (tree \generic /f /a) shows the directory

structure as follows:

   C:GENERIC

   |   GENERIC.EXE

   |   _MSSETUP.EXE

   |   _MSTEST.EXE

   |   MSCOMSTF.DLL

   |   MSCUISTF.DLL

   |   MSDETECT.INC

   |   MSDETSTF.DLL

   |   MSINSSTF.DLL

   |   MSREGDB.INC      <<<

   |   MSSHARED.INC     <<<

   |   MSSHLSTF.DLL

   |   MSUILSTF.DLL     <<<

   |   SAMPLE1.MST

   |   SETUP.EXE

   |   SETUP.LST

   |   SETUPAPI.INC

   |

   \---SOURCES

           GENERIC.C

           GENERIC.DEF

           GENERIC.H

           GENERIC.MAK

           GENERIC.OBJ

           GENERIC.RC

           GENERIC.RES

           GENERIC.STS

           MAKEFILE

User Parameters, Dialog Boxes, and Scripts

------------------------------------------

During the process of designing how to install an application, it is

necessary to determine items that the user must select or specify.

These could include optional files (such as the source directory in

this example), the drive and directory to install to, the registered

owner's name, and so forth. After gathering this information, the next

step is to modify the dialog boxes and rebuild the resource dynamic-

link library (DLL) that Setup uses. Choose one of the sample setup

scripts and modify it as required. The exercises below involve some

minor modifications to the SAMPLE1.MST script.

For more information on the resource DLL, see the Setup BDLCUI (build

customer interface) directory.

Creating the Setup Disk Images

------------------------------

The user runs the Setup program from floppy disks. The Toolkit

provides two programs that arrange the files and create floppy disks.

Dsklayt, the first layout program, runs in the Windows environment.

Use this tool to specify the files to include in the setup disk images

and the characteristics of the files. Dsklayt2, the second layout

program, runs in the MS-DOS environment (outside Windows) and reads

the layout (.LYT) file that Dsklayt creates. Dsklayt2 creates disk

images and the information (.INF) file the Setup program uses to

install files from the floppy disks to the target system.

Because the Toolkit program files must be on the first setup disk but

should not be installed on the target system, you must edit the

information file that Dsklayt2 creates.

Note the following considerations when building the file layout and

disk images:

 - Because Dsklayt cannot change directories, all Toolkit files must

   be in the same directory as the project code. Although Dsklayt

   reads subdirectories, it does not read parent directories. The

   GENERIC directory was designed as outlined above to address this

   limitation.

 - In the Dsklayt utility, place the Toolkit files on disk 1. The

   default file settings specify compressed files. Two of the Toolkit

   files, SETUP.EXE and SETUP.LST, must not be compressed. If you

   compress the other files, you must edit the SETUP.LST file to

   account for the compression. The exercises below show how to do

   this.

 - Dsklayt2 builds an .INF file, which is required by the Setup

   program. When you run Dsklayt to specify the files to include in

   the disk images, the .INF file has not yet been created, which

   prevents you from listing it in the disk images. Dsklayt2

   compensates for this and places the .INF file on setup disk 1 as

   required. However, Dsklayt2 compresses the .INF file and places a

   compressed copy of the .INF file with the extenxion .IN_ in the disk

   image directory. To work around this, copy the .INF file to the disk

   image directory before copying the files to the floppy disks.

 - The .INF file that Dsklayt2 creates instructs the Setup program to

   copy all the files. The only method of preventing the Setup program

   from copying the Toolkit files (SETUP.EXE and so forth) along with

   the program is to edit the INF file. Instructions on modifying the

   .INF file are presented in the exercises below.

 - The Dsklayt2 program provides the /k option to build 360K setup

   disks. However, most of the Toolkit files must be compressed to fit

   on a 360K disk.

Exercise 2: Using the Dsklayt Program

-------------------------------------

The Dsklayt utility runs in the Windows environment. If you use the

Toolkit often, you might find it convenient to create an icon in the

Program Manager that runs the Dsklayt utility.

When the program first starts, Dsklayt determines if you want to

create a new layout or open an existing layout. For this exercise,

create a new layout. For the source directory, specify the GENERIC

directory created in Exercise 1.

Dsklayt displays all the files in the specified directory, including

all the files in all the subdirectories. Initially, each file is

selected to be included on the setup disks and each has the following

attributes:

 - Install on any disk

 - Vital file (this file must be present or the Setup program fails)

 - Compress file when laying out setup disks

 - Check for version information

 - Always overwrite existing file on target disk

 - Decompress file when installing on target disk

 - Mark file as read-only on target disk

These options are not the best for most situations. They cause

particular problems when they are applied to the Toolkit files.

Therefore, change these default attributes as follows:

1. Select all the files by clicking the mouse on the first file in the

   files list box and dragging to the last file. Alternatively, use

   the arrow keys to place the cursor on the first file, press the

   SPACEBAR to select the file, and press SHIFT+END to select all the

   files.

2. Cancel the selection for the following options:

    - Check For Version

    - Mark As Read-Only

3. Select SETUP.EXE and clear the Compress check box.

4. Select SETUP.LST and clear the Compress check box.

5. Select all the Toolkit files. (In this exercise, these are all the

   files in the GENERIC directory except for GENERIC.EXE.) Mark these

   files for setup disk 1.

6. To create the SOURCES directory on the target disk and place the

   source files in this new directory, each file in the SOURCES

   directory must be renamed when the Setup program copies it from the

   setup disks. To rename the files:

   a. Select the first file in the SOURCES directory.

   b. Select the Rename Copied File check box.

   c. In the Edit box, type "sources\" (without quotation marks)

      followed by the name of the file.

   d. Repeat steps a-c for each file in the SOURCES directory.

   For example:

   a. Select the GENERIC.C file in the Sources directory.

   b. Select the Rename Copied File check box.

   c. Type the following in the Edit box:

         sources\generic.c

7. From the File menu, choose Save to store the layout. Give it the

   name SAMPLE1.LYT. Be sure to specify the GENERIC directory. The

   default in Dsklayt is to save the file in the MSSETUP\DISKLAY

   directory.

8. Close Dsklayt.

Exercise 3: Modifying the SETUP.LST File

----------------------------------------

The SETUP.LST file is included with the Toolkit. It lists the files

that the Setup program copies into a temporary directory. The default

SETUP.LST file assumes that the other Toolkit files are not

compressed. To correct this assumption, you must edit the file.

SETUP.LST contains two sections, labeled [Params] and [Files]. The

[Files] section of the default SETUP.LST file is as follows:

   [Files]

       sample1.mst  = sample1.mst

       sample1.inf  = sample1.inf

       setupapi.inc = setupapi.inc

       msdetect.inc = msdetect.inc

       mscomstf.dll = mscomstf.dll

       msinsstf.dll = msinsstf.dll

       msuilstf.dll = msuilstf.dll

       msshlstf.dll = msshlstf.dll

       mscuistf.dll = mscuistf.dll

       msdetstf.dll = msdetstf.dll

       _mstest.exe  = _mstest.exe

       _mssetup.exe = _mssetup.exe

It is necessary to modify entries in this section to indicate that

some of the files are compressed. To ease the process of identifying a

compressed file, the last character of the filename extension of a

compressed file is replaced with an underscore (_) character. Use any

file editor (for example, the Edit application for MS-DOS or the

Notepad application for Windows) to change the [Files] section as

follows:

   [Files]

       sample1.ms_  = sample1.mst

       sample1.inf  = sample1.inf

       setupapi.in_ = setupapi.inc

       msdetect.in_ = msdetect.inc

       mscomstf.dl_ = mscomstf.dll

       msinsstf.dl_ = msinsstf.dll

       msuilstf.dl_ = msuilstf.dll

       msshlstf.dl_ = msshlstf.dll

       mscuistf.dl_ = mscuistf.dll

       msdetstf.dl_ = msdetstf.dll

       _mstest.ex_  = _mstest.exe

       _mssetup.ex_ = _mssetup.exe

The SAMPLE1.INF file (the information file created with Dsklayt2 in

Exercise 5 below) will not be compressed. You will edit this file

later in Exercise 5.

Exercise 4: Modifying the SAMPLE1.MST Script File

-------------------------------------------------

The SAMPLE1.MST script file performs a few steps that are not

necessary for this example. SAMPLE1.MST creates an initialization

(.INI) file for the installed application and it adds a program group

and icon to the Windows Program Manager. Although these steps are

useful for an actual Setup program, they create unnecessary work for

testing purposes. This exercise modifies the setup script to eliminate

these unnecessary steps.

Instead of removing lines from the setup script, this exercise

involves inserting the comment character at the beginning of the

unnecessary lines of the file. (In an actual setup script, removing

lines is more efficient and uses less disk space.) An apostrophe (')

character at the beginning of a line marks the line as a comment.

Using a file editor, comment out lines 182 and 184-197. After

inserting the comment characters, lines 182 through 198 appear as

follows:

<line 181 follows>

    AddSectionFilesToCopyList "Files", SrcDir$, DEST$

'    AddSectionKeyFileToCopyList "Options", OPTCUR$, SrcDir$, DEST$

    CopyFilesInCopyList

'    ini$ = MakePath(DEST$, "DEMO.INI")

'    CreateIniKeyValue "WIN.INI", "MSSetup Sample 1", "Option",

OPTCUR$, cmoNone

'    CreateIniKeyValue ini$, "Section 1", "Key 1", "Value 1" , cmoNone

'    CreateIniKeyValue ini$, "Section 2", "Key 2", "Value 2" , cmoNone

'    CreateIniKeyValue ini$, "Section 3", "Key 3", "Value 3" , cmoNone

'    CreateProgmanGroup "MSSetup Sample 1", "", cmoNone

'    ShowProgmanGroup  "MSSetup Sample 1", 1, cmoNone

'    CreateProgmanItem "MSSetup Sample 1", "dialogs", "dlgedit.exe"

+MakePath(DEST$,"dialogs.res"), "", cmoOverwrite

'    CreateProgmanItem "MSSetup Sample 1", "dlgprocs.c", "notepad.exe"

+MakePath(DEST$,"dlgprocs.c"), "", cmoOverwrite

'    AddDos5Help "YOURAPP", "A brief help text for your Windows-based

application."+chr$(10)+"It can be continued on another line with

chr$(10).", cmoNone

    CloseLogFile

<last line was 198>

NOTE: Due to the margins of this document, a few of the lines in the

file "wrapped" and require more than one line above.

Exercise 5: Using the Dsklayt2 program

--------------------------------------

Dsklayt2 is an application for MS-DOS that reads the layout

information file that Dsklayt creates (in this case SAMPLE1.LYT) and

creates two items: a set of disk images and an information file. The

disk images are used to build setup disks. The Setup program uses the

information file to place the files on the target disk.

The Dsklayt2 program accepts several parameters, some of which are

required for the application to work. For this exercise, set the

current directory to the GENERIC directory created in Exercise 1 and

issue the following command:

   dsklayt2 sample1.lyt c:\disk1\sample1.inf /k144 /f /dc:\ /cc:\comp

The individual terms of this command line are as follows:

 - "dsklayt2": The filename of the Dsklayt2 application. Because the

   Toolkit installs Dsklayt2 in the Windows SDK MSSETUP\DISKLAY

   directory, the full path to this file is required unless this

   directory is in the MS-DOS PATH environment variable. If you use

   this utility often, you might want to add the directory to the PATH

   or place the full command into a batch file.

 - "sample1.lyt": The layout file produced by the Dsklayt utility.

 - "c:\disk1\sample1.inf": The filename for the created information

   file. Specifying this path ensures that Dsklayt2 places the

   information file on setup disk 1 (see the discussion of the /d

   parameter, below).

 - "/k144": The size of the setup disks. Valid options are 360 (for

   360K disks), 720 (for 720K disks), 12 (for 1.2 MB disks), 144 (for

   1.44 MB disks), and N (for a network installation).

 - "/f": Overwrite the .INF file if one already exists. This parameter

   is not required unless you run Dsklayt2 more than once and specify

   the same destination directory.

 - "/dc:\": The destination directory for the disk images. If you omit

   the /d option, Dsklayt2 creates only an .INF file (no disk images).

   Specifying "c:\" causes Dsklayt2 to create the disk images in

   directories named "disk1," "disk2," and so forth in the root

   directory of drive C.

 - "/cc:\comp": Storage for compressed files before they are copied

   into the disk images. This parameter is optional. However, if it is

   necessary to build the disk images more than once, specifying a

   location to store the compressed files speeds the process

   considerably.

After running Dsklayt2, you must edit the information file

(C:\DISK1\SAMPLE1.INF) to prevent the Toolkit files from being copied

to the target disk. Use a file editor to remove the lines in the

[Files] section that refer to the Toolkit files. The resulting file

contains only references to the files in the Generic sample

application and look like the text below. Note that the lines in the

[Files] section have been edited to fit the margins of this document.

[Source Media Descriptions]

    "1", "disk1", "_mstest.exe", "..\disk1"

[Default File Settings]

"STF_BACKUP"     = ""

"STF_COPY"       = "YES"

"STF_DECOMPRESS" = "YES"

"STF_OVERWRITE"  = "ALWAYS"

"STF_READONLY"   = "YES"

"STF_ROOT"       = ""

"STF_SETTIME"    = "YES"

"STF_TIME"       = "0"

"STF_VITAL"      = "YES"

[Files]

1, generic.h,,,, 1992-03-23,,,, !READONLY,, sources\generic.h

1, generic.rc,,,, 1992-03-23,,,, !READONLY,, sources\generic.rc

1, generic.res,,,, 1992-06-04,,,, !READONLY,, sources\generic.res

1, generic.def,,,, 1992-03-23,,,, !READONLY,, sources\generic.def

1, generic.mak,,,, 1992-05-21,,,, !READONLY,, sources\generic.mak

1, makefile,,,, 1992-03-23,,,, !READONLY,, sources\makefile

1, generic.sts,,,, 1992-06-30,,,, !READONLY,, sources\generic.sts

1, generic.c,,,, 1992-03-23,,,, !READONLY,, sources\generic.c

1, generic.obj,,,, 1992-06-04,,,, !READONLY,, sources\generic.obj

1, generic.exe,,,, 1992-06-04,,,, !READONLY,,,,,, 30456,,,,,

Exercise 6: Create Setup Disks and Test

---------------------------------------

At this stage of the process, an installation disk image is available

in the C:\DISK1 directory. (If you chose to specify 720K disks, you

probably have two disk image directories: C:\DISK1 and C:\DISK2.) To

create installation disks, copy all the files from each disk image

directory to a corresponding floppy disk (label the disks to keep them

in order).

To test the installation, place the first disk in a floppy disk drive

and run the Setup program from the Program Manager or the File

Manager. Because these exercises did not change the setup script (in

any major way) or modify the dialog boxes, the Setup program includes

some screens that are not required by this particular demonstration.

Specify any desired target drive and directory. If you choose the

default, C:\DEMO, SETUP creates a DEMO directory that contains two

files, GENERIC.EXE and a .LOG file, and a SOURCES subdirectory with

the other files.

Summary

-------

This tutorial covered the following topics:

 - Creating a target directory structure for files to install and

   placing the files into the structure

 - Using the Dsklayt utility to map the files onto setup disks

 - Using the Dsklayt2 utility to create disk images

 - Modifying the setup script and information file to make the setup

   process flow smoothly and to prevent extra files from being

   created

 - Copying the disk images onto floppy disks

 - Testing the setup disks to verify that the disks work correctly

The following directories were created by the exercises in this

tutorial if the directory names listed were used: COMP, DEMO,

DEMO\SOURCES, DISK1, GENERIC, and GENERIC\SOURCES. (If you selected

720K disks, a DISK2 directory was created as well). Delete the files

in these directories and the directories themselves, if desired.

Additional reference words: 3.10 MSSetup tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


Using Both the Retail and Debug Kernel of Windows

Article ID: Q89701

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The D2N.BAT and N2D.BAT files shipped with the Windows SDK provide a

way to switch between the retail and debug kernels of Windows within

the same installation. One problem with this approach is that the

entire kernel of Windows gets swapped during the copying process. This

article describes a way to use the debug and retail kernel at the same

time with much less overhead involved.

MORE INFORMATION

================

The following steps are involved to provide coexisting debug and

retail installations of Windows:

1. Make a copy of the SYSTEM.INI file (for example, copy it to

   SYSTEM.RET).

2. Copy renamed versions of the debug kernel .EXE files to your

   Windows system directory (for example, copy GDI.EXE from the debug

   subdirectory of the SDK disks to GDIDBG.EXE in the Windows

   subdirectory).

3. In SYSTEM.INI, add the following lines to the [boot] section:

      gdi.exe = gdidbg.exe

      <add lines for the updated USER.EXE, KRNL286.EXE, KRNL386.EXE

      and MMSYSTEM.DLL files>

4. Make a copy of the new SYSTEM.INI file (for example, copy it to

   SYSTEM.DBG).

Now you can switch between the debug and retail kernels just by

copying SYSTEM.DBG or SYSTEM.RET to SYSTEM.INI before booting Windows.

Notice that this technique does not work for the debugging version of

WIN386.EXE because that file actually reads SYSTEM.INI. To install the

debug version of WIN386.EXE, you still need to replace WIN.386 with

the version that is being shipped with the Windows Device Development

Kit.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: TlsDbgWin


Causes of Help Compiler Error 5059

Article ID: Q90292

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The Help compiler generates the following error:

   Error 5059: Not enough memory to build help file.

CAUSE

=====

Cause 1

-------

There is a graphic larger than 64K pasted directly into the RTF

source files. This violates the 64K paragraph size limit.

Cause 2

-------

The Help compiler is truly out of memory.

Cause 3

-------

There is a corrupted graphic in the project.

RESOLUTION

==========

Resolution 1

------------

The graphic must be placed into the RTF source file "by reference."

For more information on graphics in Windows Help, please see the following

article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q90291

   TITLE     : Using Graphics Within a Help File

Resolution 2

------------

All unneeded applications, device drivers, and memory-resident programs

should be unloaded before attempting to compile. If the HC31 compiler is

being used, an upgrade to the "protected mode" version of the Help compiler

is available so that larger files may be compiled. For additional

information on this compiler, please see the following article(s) in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q84931

   TITLE     : Use Extended Memory to Build Larger Windows Help Files

If any other causes of this error message are found, the information will

be posted here.

Resolution 3

------------

Replace the corrupted graphic with one that is not corrupted.

Additional reference words: 3.10 HC.EXE HC31.EXE HC31

KBCategory: kbtool

KBSubcategory: TlsHlp


.SHG Files Cannot Be Edited

Article ID: Q90293

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Once a graphic has been saved in the segmented-hypergraphic (.SHG) file

format, the appearance of the graphic can no longer be edited.

MORE INFORMATION

================

The .SHG file format is not supported by any graphics editors, and

therefore it is impossible to load a segmented hypergraphic into a graphics

editor to alter the original image. To work around this problem, a copy of

the original graphic must be archived before creating the segmented

hypergraphic. If the display needs to be altered, then the archived graphic

may be edited. To copy the hot spots to the edited graphic, two instances

of the segmented hypergraphic (hot spot) editor, SHED.EXE, need to be

opened. The first instance should contain the original .SHG file with all

of the hot spots in place. The second instance should contain the edited

graphic. The hot spots can be copied from the original .SHG file to the new

graphic using the Copy and Paste commands available in the Hotspot Editor.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsShg


DBWIN Won't Work with Text on First Line of Mono Display

Article ID: Q90374

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The DBWIN sample shipped with the Microsoft Windows Software

Development Kit version 3.1 allows your system to redirect its

debugging output to a variety of locations, including a secondary

monochrome monitor.

Due to the design of DBWIN, if the monochrome monitor contains any

text on the first line of its display when DBWIN attempts to write to

it, DBWIN will not output any text.

MORE INFORMATION

================

Because Windows does not control access to the secondary monochrome

monitor, it is possible for more than one application to write to the

monitor at the same time, producing garbled results.

To reduce the possibility of this occurring, DBWIN attempts to detect

when another application is using the monochrome display, and will

stop output if this is detected.

The method DBWIN uses to detect whether another application is using

the monochrome monitor is to check for output on the first line of the

monitor. If there is any text on this line, DBWIN assumes that another

application is using the monitor and discontinues output to the

monitor.

All output that DBWIN sends to the monochrome monitor begins on the

second line of the monitor, so it will never write on the first line.

Each time a request is made to output to the monochrome monitor

[either through an OutputDebugString() call or through a debugging

message from Windows], a check for any text on the first line is made.

If any text exists on the first line, DBWIN will not attempt to write

to the monitor because a second application might be using it.

Note that this method of checking for monochrome monitor usage is not

foolproof and may not work in all cases. In certain situations, it may

be necessary to clear the monitor manually to allow DBWIN to send text

to the monochrome monitor again. The following batch file clears the

monochrome monitor and allow DBWIN to work again:

   @echo off

   mode mono

   cls

   mode co80

In addition, the following C function clears the monochrome monitor:

extern   WORD _B000h; // Selector exported by KERNEL

void ClearMono(void) {

  _asm{

    push di               // DI is not saved automatically

    mov ax, OFFSET _B000h // Get selector to mono video memory

    mov es,ax             // Move into ES

    xor di,di             // ES:DI points to mono video memory

    mov ax, 0720h         // 0x07 = attributes, 0x20 = space character

    mov cx, 80*25         // Repeat for 80 columns by 25 rows

    rep stosw             // Store AX into (ES:DI)++, CX times

    pop di

    }

}

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsDbg


Windows Setup Toolkit Tutorial Available for Download

Article ID: Q90435

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Setup Toolkit, included with version 3.1 of the

Microsoft Windows Software Development Kit (SDK), is documented in the

"Setup Toolkit for Windows" manual, also included with the SDK.

Although this book provides a great deal of reference information

about the setup tools, it does not provide a tutorial that explains

how to use the tools.

SETTLKIT is a file in the Microsoft Software Library that contains a text

file that describes using the Setup Toolkit and a set of exercises

that build a simple set of installation disks.

Download SETTLKIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SETTLKIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SETTLKIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SETTLKIT.EXE

MORE INFORMATION

================

The SETTLKIT document demonstrates the basic use of the Microsoft

Setup Toolkit, provided with version 3.1 of the Windows SDK. The Setup

Toolkit is a collection of tools and programs designed to build a

"setup" disk--that is, a floppy disk (or group of disks) that install

one or more files onto a client's computer system.

Because the Setup program itself runs in the Windows environment, the

Toolkit is aimed primarily at building installation disks for

applications for the Windows environment. The Toolkit contains

features that allow the setup disks to copy software and other data

files to the target disk, create groups and program items in the

Windows Program Manager, and create or modify profile (.INI) files.

The tutorial does not discuss all of these features; it focuses on

using the Setup disk layout tools and on creating a "basic" setup

disk.

The tutorial discusses the following topics:

 - Selecting the files to install on the target system.

 - Including the required Toolkit files on the installation disks.

 - Creating the required directory structure on the target disk.

 - Controlling file compression and decompression.

 - Using the Dsklayt and Dsklayt2 utilities in the Setup Toolkit.

The tutorial uses the sample script file from the Toolkit (with minor

modifications). The tutorial is designed to provide a "feel" for the

capabilities of the Toolkit. To create an installation program for a

real product, additional information is required.

Additional reference words: 3.10 MSSetup tool kit softlib SETTLKIT.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsMss


DOCERR: Minimal SDK Profiler Functions Required

Article ID: Q90791

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The directions given in Chapter 10 of the Windows 3.1 SDK "Programming

Tools" manual are followed, but no profiler output is generated.

CAUSE

=====

The "Programming Tools" manual states the following on page 208:

   2. Include in your application at least the two mandatory

      Profiler functions ProfStart() and ProfStop().

      ProfStart() indicates when you want Profiler to start

      sampling code; ProfStop() indicates when you want Profiler to

      stop sampling. Other Profiler functions are optional.

This is accurate but not complete. ProfStop() does stop sampling,

but it does not write any output to the disk. Because of this, the

Profiler appears to not work.

RESOLUTION

==========

To get the Profiler to function completely, either a call to the Profiler

function ProfFlush() must be made prior to the call to ProfStop(), or the

function ProfFinish() should be used. The documentation would be more

accurate if it stated that the minimum Profile application contained a call

to ProfStart() and a call to ProfFinish(). ProfFinish() stops profile

sampling and flushes the buffer (to disk).

Additional reference words: 3.10 docerr

KBCategory: kbtool kbprg kbdocerr

KBSubcategory: TlsPrf


PRB: _MSSETUP.EXE Disappears

Article ID: Q90793

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

_MSSETUP.EXE disappears from the default directory; in fact, it deletes

itself.

CAUSE

=====

This is by design. _MSSETUP.EXE is invoked when the MSSetup script file

calls ExitExecRestart(). This function exits Windows and calls

_MSSETUP.EXE to read any commands that have been placed in _MSSETUP.BAT.

(Commands are placed in _MSSETUP.BAT when a file in the copy list is

specified as a system file that is in use during the Windows portion of

the MSSetup program.) As part of the cleanup before returning to

Windows, _MSSETUP.EXE deletes itself.

RESOLUTION

==========

If you run _MSSETUP.EXE from the MS-DOS command line or from the File

Manager, it looks for _MSSETUP.BAT, does not find it, and then deletes

itself. One way to workaround this is to compress _MSSETUP.EXE so that

it cannot be executed on its own.

MORE INFORMATION

================

NOTE: The Setup Toolkit places commands in the _MSSETUP.BAT file to copy

files that are in use during the execution of the Windows portion of the

Setup program. These files are specified in MSSetup's file copy list. For

example, if a copy list includes an update to the SHELL.DLL file, Setup

cannot update the SHELL file while Windows is running.

Additional reference words: 3.10 MSSetup tool kit

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMss


Creating Help Files Compatible with Windows 3.0 and 3.1

Article ID: Q91025

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Windows help files are a convenient tool for documenting applications

and systems. Because Windows versions 3.0 and 3.1 have different help

engines, files that are optimized for use under Windows 3.1 cannot be

used under 3.0. The Windows 3.1 Software Development Kit (SDK)

includes help compilers to build help files compatible with both help

engines. It also includes the 3.1 version of the help engine

(WINHELP.EXE) as a redistributable file. By shipping the new help

engine with their applications, developers can take advantage of the

new help features in applications built to run under Windows 3.0.

MORE INFORMATION

================

Because the functionality of the Windows 3.1 Help engine (WINHELP.EXE)

is so much greater, it is usually preferred to build help files to

take advantage of such new features as metafiles, tables, segmented

graphics, secondary help windows, and macros. If a help source file is

designed for these features, it usually cannot be compiled using the

3.0 version of the help compiler (HC30.EXE).

Because designing and maintaining two help systems is usually not

desirable, many programmers may opt for using only the Windows 3.0

Help features. Earlier files built with HC30.EXE work with the Windows

3.1 Help engine, but help files compiled with the Windows 3.1 Help compiler

(HC31.EXE) cannot be used with the Windows 3.0 Help engine.

A better solution is to design for and use the Windows 3.1 features,

compiling the file with HC31.EXE. The application's installation must

then include the new Windows Help engine and instructions (or program

support) to install it. Failure to use the correct help engine causes

the Windows 3.0 version of Windows Help to issue an error indicating

that the help file is incorrect.

The Windows 3.1 SDK comes with a number of redistributable files, two

of which are WINHELP.EXE and WINHELP.HLP. These files are in the

"redist" subdirectory in the directory where the SDK is installed.

Because the redistributable file installation is optional when the SDK

is installed, this directory may not exist. The files are also in the

normal Windows directory and can be copied from there for

redistribution.

WINHELP.EXE is the actual help engine for Windows. WINHELP.HLP is the

help file for Windows Help and should be distributed with the .EXE to

ensure that users have instructions available for using the new help

engine. Both of these files should be installed in the Windows load

directory on the target disk. They will replace the existing Windows

3.0 files. Within a Windows installation application the Windows

directory path can be obtained using the GetWindowsDirectory() API

function.

Additional reference words: 3.00 3.10 winhelp hc30 hc31 hc

KBCategory: kbtool

KBSubcategory: TlsHlp


Works for Windows Cannot Be Used to Author Help Files

Article ID: Q92423

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

RTF source files for the Windows version 3.1 Help compiler cannot be

created using Microsoft Works for Windows version 2.0.

MORE INFORMATION

================

Microsoft Works for Windows 2.0 is not capable of formatting text

using the "hidden" character attribute. This particular attribute is

used by the Windows Help compiler to signify jumps to context strings.

Because jumping to context strings is critical in a help file,

Microsoft Works for Windows 2.0 cannot be used to create the RTF

source files for the Windows Help compiler.

Additional reference words: 3.10 HC HCP link WinHelp

KBCategory: kbtool

KBSubcategory: TlsHlp


MASM 6.0 Windows Programming Sample

Article ID: Q92435

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

ASMCLOCK is a direct translation of the sample program DIGCLOCK in

Chapter 5 of Charles Petzold's "Programming Windows."

The purpose of this program is not to show the advantages of assembler

programming over C for this particular application, but to show that

programming for Microsoft(R) Windows(TM) is now possible with

Microsoft Macro Assembler (MASM) version 6.0. Because of the new

features in MASM version 6.0, this sample application was very

straightforward to develop.

NOTE: You must have the Microsoft Windows version 3.1 Software

Development Kit and MASM version 6.0 to build ASMCLOCK.

ASMCLOCK.ASM demonstrates many of the new features available with MASM

6.0. Please see the README.TXT file for more information.

Download ASMCLOCK.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ASMCLOCK.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ASMCLOCK.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ASMCLOCK.EXE

Additional reference words: 3.10 softlib ASMCLOCK.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsMisc


PRB: Setup Toolkit's SETUP.EXE Does Not Launch Windows

Article ID: Q92524

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

SETUP.EXE, from the Setup toolkit, displays the message "This program

requires Microsoft Windows" when run from the MS-DOS prompt. At other

times, SETUP.EXE successfully launches Windows and runs.

CAUSE

=====

The MS-DOS stub program for SETUP.EXE attempts to launch WIN.COM. The

stub program can do this only if the length of the path to WIN.COM is

less than or equal to the length of the path to SETUP.EXE, rounded up to

the nearest multiple of 16. If the path to WIN.COM is longer than this,

then the stub program displays the message above and returns.

RESOLUTION

==========

Run the Setup program from Windows.

Additional reference words: 3.10 MSSETUP tool kit

KBCategory: kbsetup kbtool kbprg kbprb

KBSubcategory: TlsMss


Using the Setup Toolkit Function StampResource()

Article ID: Q92525

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The StampResource() subroutine from the Setup toolkit can be used by a

Setup script to overwrite a resource in an .EXE or .DLL with the specified

data. The subroutine is useful for customizing a file's resources for the

current installation.

The syntax of a StampResource() call is:

  StampResource szSection$, szKey$, szDst$, wResType%, wResId%,

                                                     szData$, cbData%

The wResType% argument specifies the resource identification type. The

possible values are as follows:

   CURSOR        1

   BITMAP        2

   ICON          3

   MENU          4

   DIALOG        5

   STRING        6

   FONTDIR       7

   FONT          8

   ACCELERATOR   9

   RCDATA        10

   GROUP_CURSOR  12

   GROUP_ICON    14

   VERSION       16

These values are the values of the appropriate RT_ constants defined in

WINDOWS.H.

StampResource() finds the resource identified by wResType% and wResId% in

the file, and checks the size of the resource. If cbData% is less than or

equal to the size of the original resource, StampResource() overwrites the

first cbData% bytes of it; otherwise, it fails. Therefore, the script

author must make sure that cbData% is less than or equal to the size of the

original resource, and that the original resource is large enough to hold

the expected data.

MORE INFORMATION

================

The StampResource() subroutine can be used to overwrite a string resource

in a file with a user's name, company, or serial number when the file is

installed.

To overwrite a string resource, it is important to understand how string

resources are stored.

A string table consists of one or more separate resources (or segments),

each containing exactly 16 strings. The maximum length of each string is

255 bytes. One or more strings in a segment can be null or empty. The first

byte in the string specifies the number of characters in the string. For

null or empty strings, the first byte contains the value zero. The Windows

Resource Compiler (RC) allocates 16 strings per segment and uses the

identifier value to determine which segment is to contain the string.

Strings with the same upper-12 bits in their identifiers are placed in the

same segment.

With StampResource(), the wResId% is used to identify the segment; it

should be the upper-12 bits of the identifiers in the section plus 1. There

is no way to specify a specific string ID to overwrite. StampResource()

starts writing data at the beginning of the specified segment and continues

until cbData% bytes have been written. Therefore, with each call to

StampResource(), one should assume that any of the previous strings in the

segment will be overwritten. Because of this, make sure the strings that

you "stamp" never share a segment with "read-only" strings. To do this,

make the upper-12 bits of your stamp-string string identifiers different

from those of your read-only-string string identifiers.

To write the new strings for the segment, fill in szData$ with the strings

in the order of their identifiers. For simplicity's sake, it's recommended

that the string IDs be consecutive (in the .RC file), starting with one

whose lower-4 bits are 0 (zero). The string with 0000 in the lower-4 bits

of its identifier should go first. For each string, put its length followed

by the string itself in szData$. The length of szData$ should not be longer

than the total length of the original strings in the segment.

For example, an application could set up three strings, which would be

stamped with the user's name, the serial number, and the user's company

name at installation time. The application's .RC file could be arranged as

follows:

STRINGTABLE BEGIN

0x4500 "user name ------ Pad if necessary so you have room to use to"

0x4501 "serial number -- overwrite (total length of the new strings"

0x4502 "company name --- written must be less than the originals).  "

0x0001 "read-only string1"

0x0004 "read-only string2"

0x1007 "read-only string3"

0x1008 "read-only string4"

END

To stamp these strings with information collected from the user at set-up

time, call StampResource() from the Setup script with &H451 for wResId%. &H

means the number following is in hexadecimal. &H451 is the upper-12 bits of

the stamp-string string IDs plus 1.

   szUser$="Jane Doe"

   szSerial$="0123456789"

   szCo$="ACME Corp"

   szDat$=CHR$(LEN(szUser$))+szUser$+CHR$(LEN(szSerial$))+szSerial$

   szDat$=szDat$+CHR$(LEN(szCo$))+szCo$

   StampResource "Files","gen",DEST$,6,&H451,szDat$,LEN(szDat$)

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsMss


PRB: DBWIN Sample Application May Appear to Hang Windows

Article ID: Q93290

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When using the Microsoft Windows Software Development Kit (SDK) version

3.1, Windows may appear to hang if the following three items are true:

1. You are using the DBWIN sample application (DBWIN.EXE--see pages 245-

   247 of the Windows SDK "Programming Tools" manual) to catch the

   output of the debug kernel.

2. There is no other output device, other than DBWIN.

3. The "Break on Warnings" option is set in DBWIN.

CAUSE

=====

Upon entry to Windows, warnings may be displayed by the debug kernel. If

the Break on Warnings option is set as an option in the DBWIN sample

application and the Save Debug Settings is chosen from the File menu,

DBWIN will save the option in the DebugOptions setting of the WIN.INI

file under the [WINDOWS] header. Windows reads the WIN.INI file on

startup and sees that bit number 12 of the DebugOptions field under the

[WINDOWS] heading has been set (0x1000).

If bit number 12 has been set and warnings are generated before the

DBWIN application is started, the debug kernel will generate fatal exit

warnings. Because there is no output screen defined (because DBWIN is

not running yet and there is no alternate output screen), the system

will appear to be hung, when in reality it is waiting for input.

However, because DBWIN has not defined where the input will come from,

the only solution is to reboot and change the WIN.INI (or SYSTEM.INI)

settings before entering Windows (See RESOLUTION for details).

RESOLUTION

==========

To work around the problem, do one of the following:

1. Change the DebugOptions setting in the WIN.INI file under the

   [WINDOWS] heading. The value listed will be a four-digit hexadecimal

   number. The first digit must be changed to an even number to ensure

   that bit number 12 is not set (for example, 0x3000 should be changed

   to 0x2000). This method will cause the Break on Warnings option in

   DBWIN to be unchecked.

2. Add the following section to the SYSTEM.INI file:

      [debug]

      OutputTo=NUL

   A filename could replace NUL in the above statement if desired.

Once one of these procedures has been done, enter Windows and it will

come up normally.

MORE INFORMATION

================

To reproduce the problem, do the following:

1. Ensure that you are running the debug kernel (run N2D.BAT from the MS-

   DOS prompt before entering Windows).

2. Run the DBWIN sample application.

3. Choose Settings from the Options menu.

4. Ensure that the Break on Warnings check box is checked.

5. Choose OK.

6. Choose Save Debug Settings from the File menu.

To determine whether the change was successfully made, edit the WIN.INI

file and view the DebugOptions setting under the [WINDOWS] heading. Bit

number 12 should be set (the first digit will be an odd number).

Additional reference words: 3.10 DBWIN.EXE

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsDbg


Windows Help Internal Variables

Article ID: Q93645

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following information on the Windows Help internal variables is from

the Help Authoring Guide on the Microsoft Developer's Network (MSDN) CD:

   Windows Help defines a series of internal variables that can be used

   with macros. After you register a DLL function as a Help macro, you can

   specify the Windows Help internal variables as parameters to that

   function when the function appears in hot spots or macro footnotes.

   These variables are always available, and their values change depending

   on the current state of the Help file. Many DLL routines, as well as

   some standard Help macros, require the information residing in these

   variables.

   You can use any of the following Windows Help internal variables in DLL

   functions:

   Variable      Format Spec   Description

   ---------------------------------------

   hwndApp       U             Number specifying the handle (a numeric

                               identifier used by Windows) to the main

                               Help window. This variable is guaranteed

                               to be valid only while the DLL function is

                               executing.

   hwndContext   U             Number specifying the handle of the Help

                               window (either the main Help window or a

                               secondary window) that is active at the

                               time the DLL is called.

   qchPath       S             String specifying a fully qualified path

                               of the currently open Help file.

   qError        U             Long pointer to a structure containing

                               information about the most recent Windows

                               Help error.

   lTopicNo      U             Number specifying the current topic

                               number. This number is relative to the

                               order of topics in the RTF files used to

                               build the Help file. The current topic is

                               the topic displayed in the Help window

                               that is active when the DLL is called.

   hfs           U             Number specifying the handle (a numeric

                               identifier used by Windows) to the file

                               system for the currently open Help file.

   coForeground  U             Number specifying the RGB value of the

                               foreground color of the window that is

                               active when the DLL is called.

   coBackground  U             Number specifying the RGB value of the

                               background color of the window that is

                               active when the DLL is called.

Additional reference words: 3.10 Help Compiler HC31.EXE HCP.EXE

WinHelp

KBCategory: kbtool

KBSubcategory: TlsHlp


Help Topic Margins Always 1 Inch When Printed

Article ID: Q93918

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

When Windows Help topics are printed, the margins around the page are

always one inch.

As a help author, it may be desirable to set this margin to a smaller value

so that more information can fit on the page. However, there is no

interface to the Windows Help engine for a programmer to modify this value.

One inch is the default margin size for the Windows Help engine and cannot

be modified.

Additional reference words: 3.10 HCP HC HC31 Compiler Winhelp

KBCategory: kbtool

KBSubcategory: TlsHlp


New SHED.EXE Preserves Hot Spot Information

Article ID: Q93919

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SHED is a file in the Software/Data Library that contains version 3.50.784

of the Hotspot Editor (SHED.EXE) and the online help file for it

(SHED.HLP). This version of the Hotspot Editor shipped with the

Professional Edition of Visual Basic version 2.0 and is an enhanced version

of the Hotspot Editor shipped with the Windows version 3.1 Software

Development Kit (SDK).

This version of the Hotspot Editor has added a Replace option to the Edit

menu. The Replace option will replace the graphic with the bitmap or

metafile on the clipboard, while preserving the graphic's hot spot

information.

Download SHED.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SHED.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SHED.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SHED.EXE

Additional reference words: 3.10 SHED SHG softlib SHED.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsShg


Using Functions and Subroutines with Microsoft Setup

Article ID: Q93920

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

The file SUBFUNC in the Software/Data Library is a text file that describes

functions and subroutines as supported by the _MSTEST.EXE shipped with the

Microsoft Windows Setup Toolkit. _MSTEST.EXE is a limited, run-time version

of Microsoft Test that Setup uses as its driver. _MSTEST.EXE is a TestBasic

interpreter. The information in SUBFUNC is from Chapter 3 of the Microsoft

Test version 1.0 "User's Guide."

Download SUBFUNC.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SUBFUNC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SUBFUNC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SUBFUNC.EXE

Additional reference words: 3.10 MSSETUP MSTEST tool kit SoftLib

SUBFUNC.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsMss


Linking Windows-Based Applications and DLLs with /NOI

Article ID: Q94952

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The address of a function exported by an application or DLL must be

resolved by the Windows loader or a call to GetProcAddress() before the

function can be called by another application or DLL. If the function

is exported by ordinal number (or by name and ordinal number), its

address can be resolved by the ordinal number. If no ordinal number is

given for an exported function, it is said to be exported by name only

and its address must be resolved by its name.

When resolving a reference by name in one application or DLL to a function

exported by another application or DLL, the Windows loader or

GetProcAddress() will convert the function name to uppercase and perform a

case-sensitive search. If a match is not found, the Windows loader displays

a dialog box with the "Call to Undefined Dynalink" message and a button to

close the offending application. If a match is not found, GetProcAddress()

returns NULL to signal failure. One possible cause of these errors is using

the /NOIGNORECASE (/NOI) linker option.

MORE INFORMATION

================

The information in this article depends on the development tools that you

are using. If you are not using Microsoft tools, please refer to the

documentation for your development tools.

C 6.0 and C/C++ 7.0

-------------------

If an application or DLL exports __cdecl functions by name only and

is linked with /NOI (to preseve case), the Windows loader and

GetProcAddress() won't be able to resolve the function names when

performing the dynamic link, because Windows expects the names of the

exported functions to use all uppercase letters, and __cdecl functions use

mixed case. With the /NOI switch, only __pascal functions will be resolved,

because the compiler has already converted the names to all uppercase.

Without the /NOI switch, the linker will uppercase all function names,

regardless of calling convention (you can verify this in the new executable

header). Therefore the Windows loader and GetProcAddress() are able to

resolve the names.

Visual C++

----------

The linker in Visual C++ always capitalizes the names of exported functions

in the DLL executable header, regardless of whether or not you link with

/NOI, and whether they functions are declared __cdecl or not. This was done

to avoid the problems described above. One thing that can cause a problem

is if you run implib on the DLL with /NOI and link your .EXE (or another

DLL) to this implib with /NOI, you'll get unresolved externals because the

import library has the names in all uppercase letters but the .EXE is

calling them mixed-case.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsMisc


Compatibility Issues for Microsoft Windows Versions 3.x

Article ID: Q95783

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article provides guidelines for writing applications for the

Microsoft Windows versions 3.x operating system in a manner that will

produce the fewest compatibility problems when the application is run

on future versions of Windows. The discussion focuses on compatibility

issues involving Windows-based applications, Windows display drivers,

and MS-DOS-based applications.

MORE INFORMATION

================

Guidelines for Windows-Based Application Developers

---------------------------------------------------

Keep these general rules in mind when developing applications for

Microsoft Windows:

 - The golden rule of application compatibility is to adhere to the

   Microsoft Windows Software Development Kit (SDK) documentation.

   That is, do not use an application programming interface (API) that

   is not documented, and use only the features of an API that are

   documented.

 - Do not depend on the format of internal data structures to remain

   the same in the future. For example, the format of the internal

   structures used for windows (HWND), menus (HMENU), device contexts

   (HDC), regions (HRGN), bitmaps (HBITMAP), and tasks (HTASK) are

   guaranteed to change in a future version of Windows. Other internal

   structures may also change.

 - Do not assume objects are allocated in User's or GDI's data segment.

   In an attempt to remove system resource limitations, objects that

   are currently allocated in these data segments may be allocated

   elsewhere in the future. For example, assuming a window handle is

   an offset in User's data segment will probably be incorrect in

   future versions of Windows.

 - Do not replace system dynamic-link libraries (DLLs) such as

   TOOLHELP.DLL, SHELL.DLL, and COMMDLG.DLL unless you use the version

   APIs (VER.DLL). These DLLs will change in the future. The system

   will malfunction if applications replace these DLLs with the

   earlier 3.0 or 3.1 version. If your application installs these

   DLLs, double-check the code for correctness; many applications that

   attempt this do not do it correctly.

 - Test the Windows version number properly. The following code, for

   example, does not work correctly if it is run on a version of

   Windows that is numbered 4.0 because the first test of the minor

   version will fail. Surprisingly, this is a very common mistake.

      winVer = LOWORD(GetVersion());

      if (HIGHBYTE(winVer) >= 10 && LOWBYTE(winVer) >= 3)

          // run

      else

          // exit

    Use the following code instead:

      winVer = LOWORD(GetVersion());

      winVer = (((WORD)(LOBYTE(winVer))) << 8)|(WORD)HIBYTE(winVer);

      if (winVer >= 0x030A)    // NOTE: Always use a HEX value here!!!

          // run

        else

          // exit

 - Applications written for Windows versions 2.x will not be supported

   under future versions of Windows. Make sure your applications have

   been tested and built using any of the Windows versions 3.x SDKs so

   that they are marked as applications written for Windows version

   3.0 or later and can run in protected mode.

 - Do not copy Program Manager group files onto a user's disk. Use the

   Program Manager's DDE interface to add groups and group items for

   your application.

 - Do not assume minimized application windows have icon title windows.

   If your application walks the window list and assumes that a window

   with a class name of "0x8004" or "#32772" is an icon title, the

   application will not function properly in future versions of

   Windows. If your application needs to perform this operation when

   running on Windows version 3.1, write your code so that the

   application will continue to work even if it does not find the icon

   title windows.

 - Do not hard-code the pixel dimensions of menus, scroll bars, sizes

   of captions, and so on. Instead, use GetSystemMetrics to get these

   sizes. The sizes will change depending on the active display

   driver, and may be user-adjustable in the future. Also, your code

   should watch for the WM_WININICHANGED message and reinitialize the

   values accordingly.

 - Do not hard-code button colors to be the standard three shades of

   gray. Use the GetSystemColors function to obtain these colors.

   Again, watch for the WM_WININICHANGED message, and reinitialize

   these colors accordingly.

 - Those writing debuggers must use the services provided by

   TOOLHELP.DLL, rather than the services provided by the earlier

   WINDEBUG.DLL. WINDEBUG.DLL will not work in future versions of

   Windows.

 - Do not assume that GlobalWire allocates MS-DOS addressable memory.

   Your application must use GlobalDOSAlloc to obtain this type of

   memory.

 - Do not assume that GlobalAlloc with the GMEM_FIXED option allocates

   MS-DOS addressable memory. Your application must use GlobalDOSAlloc

   to obtain this type of memory.

 - Printer soft font information is currently stored in WIN.INI and is

   associated with a particular port (LPT1, for example). In the

   future, this information will be associated with a printer in order

   to be independent of the port to which the printer is connected.

 - Your application must not assume the contents of any WINOLDAP

   (MS-DOS-based application manager) data structures allocated in

   WINOLDAP's data segment. These structures may change in the future.

 - Do not over tune your application's STACKSIZE or HEAPSIZE settings in

   the application's .DEF file. Some developers have tuned these

   settings (STACKSIZE, in particular) in their applications to supply

   exactly enough space to run on Windows version 3.0 or 3.1. These

   applications sometimes have problems because different Windows

   display drivers have different stack depth characteristics. Future

   versions of Windows will compound this problem because the stack

   depth will change for most of the core components (GDI, Kernel,

   User, and so forth). It is recommended that at least an additional

   2K be added to the minimum STACKSIZE and HEAPSIZE settings.

Guidelines for Display Driver Developers

----------------------------------------

Keep these points in mind when developing display drivers for Windows:

 - The meaning of the WindHand field in EXTPAINTSTRUC may be changed

   for enhanced-mode grabbers. WindHand is the HWND of the grabber

   child window inside the WINOLDAP window. All grabber painting

   should be restricted to this window. Grabbers were not supposed to

   use WindHand for anything beyond calling GetClientRect, GetDC, and

   so on.

 - Grabbers should not use the EPStatusFlags bits other than fFocus,

   fVValid, fSelect, and fGrbProb. Some bits that are private to

   WINOLDAPP were accidentally included in the DDK header files

   although not used in any Microsoft-distributed grabber sample

   source.

Guidelines for MS-DOS-based Application Developers

--------------------------------------------------

If you develop applications for MS-DOS, keep these rules in mind:

 - Make sure your application works properly in a Windows version 3.1

   MS-DOS box. Especially, make sure your Setup program functions in a

   Windows MS-DOS box. For example, writing over Program Manager group

   files or altering WIN.INI or SYSTEM.INI while Windows is running

   would be improper things to do. Even though the application is

   MS-DOS-based, consider writing a Windows-based Setup program,

   especially if your setup process needs to perform operations such

   as altering WIN.INI or SYSTEM.INI.

 - Do not assume the location of the system file table (SFT) or MS-DOS

   buffers. These may be moved into high memory to provide extra

   conventional memory. In general, all internal MS-DOS data

   structures may be moved into high memory in the future.

 - Do not assume sizes of internal MS-DOS data structures. For example,

   do not assume that a drive parameter block (DPB) is 21h bytes long

   as some applications have. The format of data structures, such as

   these that are easy to find and traverse, may change in future

   versions of MS-DOS. Use documented Interrupt 21h calls to obtain

   information such as this. For example, DPBs can be obtained using

   Interrupt 21h functions, 1Fh, and 32h.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: TlsCompat


PRB: LINK Error L2022: Export Undefined

Article ID: Q96186

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When an application is processed by the Microsoft Segmented-Executable

Linker, the error message L2022 "export undefined" is generated.

Two possible causes of this error, and the corresponding steps to resolve

the problem, follow.

CAUSE

=====

CAUSE 1

-------

The name of a function that is used in the application is not

properly listed in the EXPORTS statement in the module definition

(DEF) file.

CAUSE 2

-------

Unprintable characters appear at the end of the EXPORTS statement

in the module definition (DEF) file.

RESOLUTION

==========

RESOLUTION 1

------------

Determine the correct spelling of the label and correct the source

file or the DEF file. For example, the names of functions called

with the PASCAL calling convention are implicitly converted to

uppercase letters. In functions exported with the CDECL calling

convention, the case of the function name is preserved, and an

underscore (_) is added to the function name as a prefix.

RESOLUTION 2

------------

Modify the DEF file to remove the unwanted characters. Also make

sure that the DEF file is saved from the text editor or word

processor as plain text.

MORE INFORMATION

================

The linker /INFORMATION option provides additional information about

the linking process to assist in tracking and correcting errors.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: TlsMisc


PRB: Starting Heap Walker Results in a GP Fault

Article ID: Q97759

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the Microsoft Windows Heap Walker application (HEAPWALK.EXE) that is

shipped with the Microsoft Windows versions 3.0 and 3.1 SDK is started or

if another application is started after Heap Walker is running, a general

protection (GP) fault may occur with the following message:

   HEAPWALK caused a general Protection Fault in

   module HEAPWALK.EXE at xxxx.xxxx.

If Dr. Watson is running, it reports the fault as:

   'Exceed Segment Bounds (Write)' fault at HEAPWALK xxxx:xxxx

CAUSE

=====

There is a bug in the Heap Walker application that results in a GP

fault when there are too many objects in the global heap. This

problem happens more often when many applications are running in

the system. The problem can also happen, however, when only a few

applications are running in the system but some of them are

allocating a number of global memory blocks.

RESOLUTION

==========

Do one of the following to resolve this problem:

 - Do not run the Heap Walker application when many applications are

   running in the system. If the GP fault occurs, exit and restart

   Windows, and run Heap Walker only when a few applications are

   running.

   -or-

 - Use the updated version of the Heap Walker application available

   in the Software Library. The updated version, called

   NEWHEAP, corrects the GP fault problem.

Download NEWHEAP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for NEWHEAP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NEWHEAP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NEWHEAP.EXE

MORE INFORMATION

================

When the Heap Walker application is started, it tries to list all the

objects in the global heap in its main window. It uses the Toolhelp

Library to walk the global heap, and it keeps track of all these

objects in a linked list. If there are a large number of objects in

the global heap, the linked list would grow beyond a 64K segment. Any

global object that grows larger than a 64K segment must be accessed

using huge pointers, otherwise an error will occur. In the Heap Walker

application, the linked list is being accessed using far pointers

instead of huge pointers. This results in a GP fault.

The updated version of Heap Walker corrects this problem by using huge

pointers instead of far pointers to access the linked list.

Additional reference words: 3.00 3.10 crash gpf gp-fault heapwalker

KBCategory: kbtool kbprg kbfile kbprb

KBSubcategory: TlsHeapWalk


PRB: Combined Windows 3.0 and 3.1 Applications

Article ID: Q99336

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0

---------------------------------------------------------------------

SYMPTOMS

========

When a combined Windows 3.0 and 3.1 application is run under the debugging

version of Windows 3.0, during load time, a Fatal Exit message "Invalid

Ordinal Reference" is displayed on the debug terminal followed by a stack

trace.

Note, however, that the application continues to load and run successfully,

and therefore this error message can be ignored as long as the Windows 3.1

function is not actually called.

CAUSE

=====

While loading an application, the Windows 3.0 kernel attempts to fix up

references to all function calls in the application. At load time, the

Windows 3.0 kernel is unaware of the version checking being done on the

Windows 3.1-specific calls. The version 3.0 kernel will attempt to fix up

the references to the Windows 3.1 calls too, which are undefined, and

therefore the Fatal Exit message is generated.

RESOLUTION

==========

The Fatal Exit message can be ignored because the application will run

successfully.

If this behavior (the Fatal Exit message) is not satisfactory, use the

following workaround to call Windows 3.1-specific calls in a Windows 3.0

application without generating any Fatal Exit messages:

extern BOOL fWin31;

  // Assuming fWin31 is initialized appropriately using GetVersion().

       if (fWin31)

       {

          // Get the address of the Window 3.1-specific function.

         // First, load either USER.EXE, GDI.EXE, or KERNEL.EXE,

         // depending on which DLL the function resides in.

          LoadLibrary(...);

          // Get the address of that function using GetProcAddress().

          lpfnWin31FuncAddr = GetProcAddress(...);

          // Use this address to make the function call.

          (*lpfnWin31FuncAddr)(...);

        }

This method will not generate a Fatal Exit message under the debug version

of Windows 3.0, because there is no direct reference made to a Windows 3.1

function.

For a quick reference on how this method works, please see the DIBVIEW

sample provided with the Windows SDK. The source file PRINT.C adopts this

same technique in the FindGDIFunction() routine before calling any GDI

functions specific to Windows 3.1.

MORE INFORMATION

================

Microsoft Windows version 3.0 applications can be written to conditionally

link to and use Windows version 3.1 functions to take advantage of the

newer features when running under Windows 3.1. This is explained in the

"Combined Windows 3.0 and 3.1 Applications" section on page 31 of the

Microsoft Windows SDK "Getting Started" manual for version 3.1.

This behavior may not be suitable for certain applications or could lead to

other problems. For example, on systems that do not have a debug terminal

connected to the COM1 port to receive debug information, Kernel will

display a "Cannot write to device AUX" message box or the system might

freeze. The debug message could be redirected from the AUX device to some

other destination, if desired. For information on how to do this, please

query on the following words in the Microsoft Knowledge Base:

   redirect debug information

Additional reference words: 3.10 RIP

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsDbgWin


PRB: MASM Code Using CMACROS.INC Does Not Build Correctly

Article ID: Q100407

SYMPTOMS

========

Attempting to build a Windows-based application with MASM code using a

CMACROS.INC header file causes errors to be generated by the macro

assembler.

CAUSE

=====

The CMACROS.INC file is incompatible with the version of MASM being

used.

RESOLUTION

==========

When using MASM version 6.x, use the version of CMACROS.INC that comes

with MASM. When using MASM version 5.1, use the version of CMACROS.INC

that comes with the development product you are using, such as the

Windows Software Development Kit (SDK) or the Windows Device Driver

Kit (DDK).

MORE INFORMATION

================

MASM has changed considerably from version 5.1 to versions 6.x; the

changes to the assembler include the removal of the second assembly

pass and additions or modifications to the behavior of assembler

directives. A complete list of the differences can be found in the

product documentation of MASM versions 6.0 and later. Because of these

changes, versions of CMACROS.INC compatible with MASM 5.1 are not

compatible with MASM 6.x; likewise, versions of CMACROS.INC compatible

with MASM 6.x are not compatible with MASM 5.1.

Most of Microsoft's development products include a version of

CMACROS.INC that is compatible with MASM 5.1. Use this version of

CMACROS.INC with MASM 5.1. If MASM version 6.0 or later is being used,

use the CMACROS.INC that comes with it instead of the one that comes

with the development product.

Additional reference words: 3.10

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMisc


PRB: Help Compiler Causes Fatal Exit or Other System Failure

Article ID: Q104917

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

SYMPTOMS

========

When running HC31.EXE or HCP.EXE in Windows 3.1, a dialog box is

displayed that indicates something similar to "a GP fault or exception

has occurred" or "the System has been violated. Please save your files

and close down Windows."

When running in NT, the system will hang or you will receive an OS/2

application faulted at CS = 0x4007.

CAUSE

=====

There is an internal limit of 32K that is getting processed.

RESOLUTION

==========

There is an updated version of HCP.EXE (version 3.10.505) that sets

the limit to 64K.

Download HC505.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S14344.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HC505.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HC505.EXE

HC505.EXE contains four files: HC.EXE, HCP.EXE, and two .ERR files.

MORE INFORMATION

================

HC.EXE and HCP.EXE versions 3.10.505 correct the following problems:

 - Some new RTF items (font header information) that Word for Windows

   version 6.0 generates.

 - Increase the number of entries (around 8,000) in the map section

   and the alias sections in the .HPJ file.

 - Increase the number of bitmaps in the .RTF file to around 2,970.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbprg kbfile kbprb

KBSubcategory: TlsHlp


Using the "BR" Command in WDEB386.EXE

Article ID: Q105275

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

--------------------------------------------------------------------

The "BR" command in WDEB386.EXE uses the debug registers of the Intel

386 and above processors to break into the debugger on memory

accesses. These accesses can be in byte, word, or dword sizes

involving a read, write, or execute instruction. Because the BR

command is very specific as to the type of memory access it will trap,

care must be taken to choose the correct combination of BR settings in

order to obtain all possible cases:

   E == execute access

   W == write access

   R == read access

   1 == byte sized access

   2 == word sized access

   4 == dword sized access

When a break into the debugger is required when a memory location is

modified, set a few BR breakpoints on a Write operation giving the

three different operand sizes:

   BR W1 seg:off

   BR W2 seg:off

   BR W4 seg:off

This should cover all possible cases of the memory being touched.

Additional reference words: 3.10 3.00 breakpoint br

KBCategory: kbtool

KBSubcategory: TlsWdeb


Win32 Resource Localization Tools Available

Article ID: Q110894

--------------------------------------------------------------------------

The information in this article applies to:

 - Resource Localization Tools shipped on the Microsoft Developer Network

   (MSDN) Development Platform CD

--------------------------------------------------------------------------

The Resource Localization tools (RLTools) shipped with the Microsoft

Developer Network (MSDN) Development Platform CD are available for download

from the Microsoft Software Library.

RLTOOLS.EXE contains the following files:

   README.TXT

   RLADMIN.EXE

   RLEDIT.EXE

   RLMAN.DOC

   RLMAN.EXE

   RLMAN.HLP

   RLMAN.TXT

   RLQUIKED.EXE

   RLTOOLS.DOC

   RLTOOLS.HLP

   RLTOOLS.TXT

   TUTOR32.DOC

NOTE: This set of tools runs on Windows NT only and is for localizing files

that contain Win32 resources. The tools will not operate on Windows 3.1 or

Windows 95.

Download RLTOOLS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download RLTOOLS.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RLTOOLS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RLTOOLS.EXE

Additional reference words: 3.10 softlib RLTOOLS.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsMisc


The Unexpected QuickWin Error

Article ID: Q112389

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Applications for Microsoft Windows developed with the Windows SDK may

display an error message box with the error:

    "Unexpected QuickWin Error"

MORE INFORMATION

================

There are several possible causes for this error:

 - A QuickWin application caused an unexpected application error (UAE) or

   general protect (GP) fault.

   - or -

 - A Microsoft Windows-based application that is not a QuickWin application

   called a QuickWin function. If execution of a non-QuickWin application

   for Windows results in this error, one of the QuickWin functions was

   linked and executed in the application.

   - or -

 - Possible mismatch of memory model libraries (for example, building a

   large model application but using SLIBCEW, the small model library for

   Windows.)

   - or -

 - Possible stray function pointers that accidentally call one of the

   QuickWin stubs.

   - or -

 - You may have attempted to use an invalid file handle with one of the I/O

   functions.

The run-time libraries for Windows (SLIBCEW, MLIBCEW, CLIBCEW, and LLIBCEW)

contain stubs to the QuickWin functions. Therefore, the linker will not

give an error when linking with a QuickWin function from a non-QuickWin

application for Windows. However, when the function executes, an error

message box with the error "Unexpected QuickWin Error" will be displayed.

The following functions are in the QuickWin library:

   _fwopen                    _wgopen

   _inchar                    _wgsetactive

   _wabout                    _wmenuclick

   _wclose                    _wopen

   _wgclose                   _wsetexit

   _wgetexit                  _wsetfocus

   _wgetfocus                 _wsetscreenbuf

   _wgetscreenbuf             _wsetsize

   _wgetsize                  _wyield

   _wggetactive

For further information regarding QuickWin applications and the QuickWin

routines, refer to the Language Help file of Visual C++ or the Microsoft

Visual C++ "Run-Time Library Reference" manual.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: TlsMisc


Reasons for Failure of SetRestartDir

Article ID: Q113187

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

The SetRestartDir subroutine from the Setup Toolkit will return 0 (zero)

for any of the following reasons:

 - The restart directory has already been set by an earlier call to

   SetRestartDir from the setup script.

 - The value of the STF_CWDDIR symbol is an empty string or it is not a

   valid directory.

 - _MSSETUP.EXE is not in the STF_CWDDIR directory. This is true if

   MSSETUP.EXE is not included in the [Files] section of the SETUP.LST

   file.

 - _MSSETUP.EXE cannot be copied from the STF_CWDDIR directory to the

   restart directory.

 - _MSSETUP._Q_, a temporary file created in the temporary directory

   specified in SETUP.LST by SETUP.EXE, cannot be copied to the restart

   directory.

 - The restart directory specified is invalid. The syntax for the directory

   name is:

      drive:\[dir[\subdir...][\]]

Additional reference words: 3.10 mssetup

KBCategory: kbtool

KBSubcategory: TlsMss


PRB: Setup Toolkit DoMsgBox Shows Wrong Buttons or Icons

Article ID: Q113939

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Only the MB_OK, MB_ICONHAND, and MB_TASKMODAL styles are recognized in the

wType% parameter. Any additional styles are ignored and the message box

will only show the OK button.

CAUSE

=====

Only the MB_OK, MB_ICONHAND, and MB_TASKMODIAL constants are defined in

SETUPAPI.INC. Although DoMsgBox() can use all the constants described in

the Microsoft Windows 3.1 SDK under the MessageBox() function, these

constants are not defined in SETUPAPI.INC and hence are ignored in the call

to DoMsgBox().

RESOLUTION

==========

Modify SETUPAPI.INC to include definitions of the missing style constants

or pass the numerical value in the wType% parameter rather than the SDK

constant.

Below is a list of all of the possible styles you can specify in the wType%

parameter of the DoMsgBox() function. Cut and paste the needed constants

into your SETUPAPI.INC file.

CONST MB_OK                = 0

CONST MB_OKCANCEL          = 1

CONST MB_ABORTRETRYIGNORE  = 2

CONST MB_YESNOCANCEL       = 3

CONST MB_YESNO             = 4

CONST MB_RETRYCANCEL       = 5

CONST MB_ICONHAND          = 16

CONST MB_ICONQUESTION      = 32

CONST MB_ICONEXCLAMATION   = 48

CONST MB_ICONASTERISK      = 64

CONST MB_ICONINFORMATION   = 64

CONST MB_ICONSTOP          = 16

CONST MB_DEFBUTTON1        = 0

CONST MB_DEFBUTTON2        = 256

CONST MB_DEFBUTTON3        = 512

CONST MB_APPLMODAL         = 0

CONST MB_SYSTEMMODAL       = 4096

CONST MB_TASKMODAL         = 8192

Additional reference words: MSSetup tool kit

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMss


PRB: Setup Toolkit Error "Parser out of memory"

Article ID: Q114474

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the setup program created by the Microsoft Setup Toolkit is reading

the script, the following error message is given:

   Parser out of memory

CAUSE

=====

This means that the script interpreter has exceeded its memory limit on

some memory object. The memory object could be a data segment, a code

segment, or one of the parser tables. There is no way to know which memory

object it is. The chance of running out of interpreter table space is rare

-- you will almost always run out of code or data space first.

RESOLUTION

==========

Try breaking the script into multiple scripts and try running them

independently. This can be done by using Microsoft Test's RUN command. For

example:

      RUN "_mstest script1.mst"

Other tricks that can bed used to reduce the size of the code and data

segments include:

1. Eliminate excess code, by using only those .INC files that are

   needed. For example, if you are not using the registration database,

   do not include MSREGDB.INC.

2. Within each .INC files, comment out unused functions.

3. DLL calls are expensive in terms of code generation. If a script

   makes frequent calls to a function in a DLL, it might be better to

   place the call to that function in a wrapper function/subroutine

   within the script file. This will reduce memory consumption.

4. Finally, consider using text files to hold your strings and read them

   in at run time.

REFERENCE

=========

For additional information, please see the following article(s) in the

Microsoft Knowledge Base:

ARTICLE-ID: Q87455

TITLE     : PRB: Test "Parser Out of Memory" Error

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: TlsMss


Using the Setup Toolkit's GetLocalHardDrivesList Function

Article ID: Q114607

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

The subroutine GetLocalHardDrivesList() takes one parameter, szSymbol$.

This parameter is used to specify a symbol name that will receive the hard

drive list. The parameter is not a destination string for the return value.

The correct way to use the function is to specify a symbol name, such as

"drives", and then use GetSymbolValue() or GetListItem() with

GetListLength() to obtain the local drive letters.

MORE INFORMATION

================

The following is a .MST script that demonstrates how to use this function:

'$include 'setupapi.inc'

'$include 'msdetect.inc'

INIT:

    GetLocalHardDrivesList "drives"

    '' Obtain and display list of local hard drives.

    Drives$=GetSymbolValue ("drives")

    pause Drives$

    '' Cycle through list and display them one at a time.

    for i%=1 to GetListLength ("drives")

        pause GetListItem ("drives", i)

    next

QUIT:

    end

Additional reference words: 3.10

KBCategory: kbprg kbcode

KBSubcategory: TlsMss


PRB: Setup Toolkit Cancel Button Not Working On Disk Changes

Article ID: Q114608

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The Setup Toolkit function CopyFilesInCopyList() automatically presents

disk change dialog boxes to the user when the next disk in the setup is

required. This dialog box has OK and CANCEL buttons. Under certain

circumstances, pressing the CANCEL button is ignored.

RESOLUTION

==========

There is no way to change this behavior. The disk change dialog box is

managed by CopyFilesInCopyList(). The only way to avoid this behavior is to

make sure there is at least one "vital" file on each disk.

MORE INFORMATION

================

If all the files on the requested disk are marked as "non vital" in

DSKLAYT, pressing the CANCEL button will cause the requested disk to be

skipped and a prompt for the next disk to be displayed. The expected

behavior is for setup to be canceled when the CANCEL button is pressed.

Additional reference words: 3.10 mssetup setup toolkit

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMss


Running WINHELP.EXE with Command Line Switches

Article ID: Q115183

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

It is possible to use certain command-line arguments on the running

of WINHELP.EXE to go immediately to areas of the help file other than

the contents.

MORE INFORMATION

================

When calling WINHELP.EXE, but before specifying the help file name,

use the following switches:

   -k  Go to keyword (set up with the K footnote within the help file).

   -n  Go to context number (set up with the # footnote within the help

       file).

   -i  Go to context ID (set up with the # footnote within the help file

       using a #defined string).

   -h  Run WINHELP.EXE with the WINHELP.HLP file (no other help file is

       necessary).

EXAMPLES

========

The following examples can be tested by typing them into the Run

dialog box that opens when you choose Run from the File menu in

the Program Manager.

To run the file MYHELP.HLP and jump to the keyword "jumphere", type the

following:

      WINHELP.EXE -kjumphere myhelp.hlp

To run the file TEST.HLP and jump to the topic with context ID number 101,

type the following:

      WINHELP.EXE -n101 test.hlp

To run the file CIJUMP.HLP and jump to the topic with context ID

"MY_JUMPID" (which had previously been set within the .HLP file with

#define MY_JUMPID 102), type the following:

      WINHELP.EXE -iMY_JUMPID cijump.hlp

To run the file "Help on Help", type the following:

      WINHELP.EXE -h

Additional reference words: 3.10 hc hcp

KBCategory: kbtool

KBSubcategory: TlsHlp


Installing and Using the Debugging Version of Windows

Article ID: Q118891

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The debugging version of Windows replaces the core Windows code with code

that provides additional error checking and reporting not in the standard

(non-debugging) version of Windows. This information is useful if you are a

developer testing your own application under Windows. The debugging version

of Windows will point you to resource leaks and errors that go otherwise

undetected; therefore, it is a good idea to run your application under the

debugging version at least once, even if the program appears to run without

any problems.

You can install the debugging version of Windows from either the Windows

SDK or the Visual C++ Professional Edition. General installation and use

guidelines are available in the SDK manual "Getting Started" and the Visual

C++ manual "Professional Tools User's Guides." This article provides

additional information on these subjects.

MORE INFORMATION

================

First, follow the guidelines in your manual to install the debugging

version of Windows. If you have already installed the SDK or Visual C++ and

did not choose to install the debugging version, run the setup program

again. You only have to install the debugging version at this point. The

debugging version is called the "debug kernel." The term "kernel" refers to

the operating system core. In Windows, the kernel consists of the GDI.EXE,

KRNL386.EXE, and USER.EXE files.

The files that ship with the Windows version 3.1 SDK or Visual C++ work

with both Windows version 3.1 and Windows for Workgroups (WFW) version

3.11. The .SYM files are specific to the version of Windows that you are

running. If you install from Visual C++ version 1.5 and are using WFW,

after installing you need to copy the GDI.SYM, KRNL386.SYM, and USER.SYM

files from the CDs MSVC\NODEBUG\WFW311 directory to your MSVC\NODEBUG

directory, overwriting the Windows version 3.1 files that are currently in

that directory. However, if you are installing from the SDK or Visual C++

version 1.0, you need to copy those three files from your system directory

before you run the debugging version of Windows. If you happen to use the

wrong .SYM files when not in debugging mode, Windows will still run OK.

However, programs like Dr. Watson that use .SYM files will occasionally

have output that is off by a couple of bytes. If you need the WFW files,

they are available on CompuServe in the WinSDK forum, in the file

DBG311.ZIP. (Make sure to use the -d flag when using PKUNZIP to tell it to

maintain the directory structure.)

Once the debugging version is installed, you will have the following batch

files available to switch between the non-debugging and the debugging

version of Windows: N2D.BAT and D2N.BAT. By default, they are in either the

WINDEV\BIN or the MSVC\BIN directory. You will probably want to switch to

the non-debugging version when you do not need the extra diagnostics of the

debugging version, because the debugging version runs significantly slower

due to the increased error checking. When you run the debugging version of

Windows, you will see the phrase "Enhanced Mode Debug Windows" in the lower

right-hand corner of your screen.

If you start the debugging version of Windows and the error "Cannot write

to device AUX" displays, most likely COM1 is not available and you should

direct the debugging output elsewhere. For additional information, please

see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q86263

   TITLE     : Redirecting Debugging Information Under Windows

You can control the level of diagnostic information by using the debugging

version of Windows. The groups of output options are break options, debug

options, and trace options. The debug option "break with INT 3" is useful

if you are running your program under the debugger: when the program causes

a general-protection (GP) fault, the debugger stops on the line of code

where the fault occurred. In general, it is a good idea to check all of the

trace options and also clear the "Print on Break Only" check box so that

printing occurs synchronously. For more information on the debugging

version of Windows and the debugging options, see the DBWIN.TXT file that

is included with the DBWIN sample and the "Windows Debugging

Version/Debugging Programs" topic in the SDK help file.

You can use OutputDebugString() or DebugOutput() in your own application to

print debugging output. These APIs are easier to use than MessageBox().

When you run the debugging version of Windows, you may notice errors from

other Windows-based applications that you are running. Other applications

can even cause general protection faults or machine hangs when they are run

under the debugging version. This is a sign that the application developer

did not test the application under the debugging version of Windows. If you

have an application in your startup group that prevents the debugging

version of Windows from loading, hold down the Shift key while booting so

that the applications in your startup group are not started.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsDbgWin


Microsoft Development Library Demo Available in

Article ID: Q120728

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Development Library

---------------------------------------------------------------------

The Microsoft Development Library is a comprehensive reference for

developers who are developing applications for Microsoft Windows. The

Microsoft Development Library contains sample code, technical articles,

specifications, utilities, product documentation, the Microsoft Knowledge

Base, and more.

A demo of the Microsoft Development Library is now available for download

from the Microsoft Software Library (MSL). This demo delivers the full

functionality of the Microsoft Development Library applied to a subset of

the Library's contents, along with a comprehensive listing of everything on

the Library CD-ROM. The Library is available only through membership in the

Microsoft Developer Network. For more information about the Microsoft

Developer Network, please call (800) 759-5474.

Download MSDNDEMO.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MSDNDEMO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MSDNDEMO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get MSDNDEMO.EXE

Additional reference words: sample cdrom platform msdnl1

KBCategory: kbref kbfile

KBSubcategory: TlsMisc


PRB: Heap Walker's Object: USER LocalWalk Doesn't Track Data

Article ID: Q124271

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Using the Microsoft Windows Heap Walker application (HEAPWALK.EXE), you

choose Object:USER Localwalk(DATASEG) to do a local walk of the USER heap.

After saving the results in a file, you open the file to discover all the

count and size values are zero as in this example:

-----------------------------------------

OBJECT              COUNT      SIZE

Class                   0         0

Window                  0         0

String                  0         0

Menu                    0         0

Clipbrd                 0         0

ComboBox                0         0

Palette                 0         0

EditCtrl                0         0

WindowList              0         0

OwnerDraw               0         0

SPB                     0         0

CheckPoint              0         0

DCE                     0         0

MoveWinPos              0         0

Properties              0         0

ListBox                 0         0

Misc                    0         0

Atoms                   0         0

LockInputState          0         0

HookList                0         0

UserSeeUserDo           0         0

HotKeyList              0         0

Handle Table            0         0

-----------------------------------------

CAUSE

=====

The Heap Walker application obtains the information for the chart by

walking the USER module's local heap using the LocalFirst() and LocalNext()

functions in the ToolHelp library. The entries correspond to the wType

values in the LOCALENTRY structure of the ToolHelp library. The

documentation on the LOCALENTRY structure in the Windows SDK Help file

states that these wType values are included only in the debugging version

of USER.EXE, not in the retail version. Therefore, because Heap Walker uses

ToolHelp to obtain these values, no values are found in the retail version

of Windows.

RESOLUTION

==========

Switch to the Debug version of Windows, and run the Heap Walker

application. This will produce correct results. For more information on the

debugging version of Windows and how to switch to it, search on the phrase

"Windows Debugging Version" in the Windows version 3.1 SDK Help file

(WIN31WH.HLP) or refer to the topic "Windows Debugging Version" in Appendix

C of the "Programming Tools for Windows" manual, which is part of the

Visual C++ version 1.50 "Professional Tools User's Guide."

NOTE: When you try to reproduce the same behaviour in the Heap Walker

application for GDI heap by choosing Object:GDI LocalWalk(DATASEG), you

will see that the table shows correct values for individual GDI objects.

This is by design.

STATUS

======

This behavior is by design.

MORE INFORMATION

================

Steps to Reproduce Behavior

---------------------------

1. Run the Microsoft Windows Heap Walker application (HEAPWALK.EXE) shipped

   with the Microsoft Windows versions 3.0 and 3.1 SDK or the Visual C++

   version 1.50.

2. Choose the Object:USER Localwalk(DATASEG) menu option to do a local walk

   of the USER heap.

3. From the USER Heap(Local Walk) window, choose Heap:Save.

4. Open the file created by Heap Walker (usually \WINDOWS\HWL00.TXT) with a

   text editor, and scroll to the bottom.

5. Notice that there are columns for OBJECT, COUNT, and SIZE, but all the

   COUNT and SIZE values are zeros.

Additional reference words: 3.00 3.10 heapwalker

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHeapWalk


Window Handles of Global Objects

Article ID: Q10213

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

A handle is a unique, fixed identifier for a global object. Handles exist

to allow easy, indirect access to an object that may move in memory.

Handles are unique only among the objects to which they refer. A handle to

a window will always be different from all other handles to windows, but it

could have the same value as a handle to a brush (or to any other object).

It is safe to hold onto a window handle (or any handle) of a global object.

As long as that object exists, its handle will not change.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Using EndPaint() and BeginPaint()

Article ID: Q10216

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The PAINTSTRUCT structure contains information for an application that

can be used to paint the client area of a window owned by that

application.

The PAINTSTRUCT data structure is automatically updated by the BeginPaint()

function; if a window has been restored, BeginPaint() will update the

PAINTSTRUCT fields (for example, fRestore). The application would be

duplicating effort if it also updated the fields of the PAINTSTRUCT after a

window is restored. The EndPaint() procedure is required after

BeginPaint(). The application only needs to be concerned about its own

paint procedure that comes between BeginPaint() and EndPaint().

For additional information on the PAINTSTRUCT data structure, see page 7-55

in the "Microsoft Windows Software Development Kit Reference Volume 2" for

version 3.0 of the Windows SDK, and page 384 in the "Microsoft Windows

Software Development Kit Programmer's Reference, Volume 3: Messages,

Structures, and Macros" for version 3.1 of the Windows SDK.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrPnt


Changing the Name of a Second Instance of an Application

Article ID: Q10856

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When running a Windows-based application with multiple instances, check

hPrevInstance if you need to know if your instance is the first instance.

If it is NULL, this is a new instance of static data; if it is not NULL, it

is not a new instance of static data. You can give the instance a unique

name by doing either of the following:

1. Use CreateWindow() and give it a unique name.

2. Use GetWindowLong() to access the CREATSTRUCT structure passed when

   processing a WM_CREATE message and specifically change the lpszName

   field (if you want to change the caption name on the existing,

   already named instance).

You cannot change the icon name dynamically. You should use the second

method to update the icon name from untitled to a unique name.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Changing Window Colors with Control Panel

Article ID: Q11246

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In Windows, changing the screen background color or the test color

will affect the following programs:

   Notepad        MS-DOS Executive

   Clock          PIF Editor

   Control        Spooler Panel

   Calendar       Terminal

   Clipboard      Write

However, the following programs are not affected:

   Calculator     Reversi

   Cardfile       COMMAND.COM

   Paint

MORE INFORMATION

================

It is up to the application to look in the WIN.INI file to see what

[color] preferences are selected. Some applications do not change

because either they do not look in the WIN.INI file for those colors,

or the applications choose to ignore them.

For an application to be aware of system color changes, the

WM_SYSCOLORCHANGE message must be used in the Windows procedures.

For example, suppose a static hBrush is in the WndProc for repaint

purposes. To be aware of system color changes, update the brush based

on system color changes by doing something similar to the following:

 case WM_SYSCOLORCHANGE:

    DeleteObject(hBrush);

    hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));

    return 0;

Additional reference words: 3.10 3.00

KBCategory: kbprg

KBSubcategory: UsrPnt


Windows Resource Numbering Starts at 1

Article ID: Q11636

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Numbered resources in Windows must start at 1, not zero. Beginning with the

MS-DOS version 4.0 executable format, executable segments are numbered from

1, and resources are implemented as independent segments. Therefore,

resources are numbered from 1.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubCategory: UsrRsc


How to Change a Window's Parent

Article ID: Q12172

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following information describes how to change a window's parent in

Windows versions 2.x and 3.x.

The correct way to do this in Windows versions 2.x is to destroy the

child and then re-create the child with the proper handle to the

parent. The following steps can be used to do this:

1. Do a ShowWindow(hWnd, HIDE_WINDOW) call.

2. Change the handle to the child using the SetWindowWord function.

3. Do a ShowWindow(hWnd, SHOW_WINDOW) call.

NOTE: Microsoft does not recommend that this method and does not

guarantee it to work in future releases of Windows.

In Windows versions 3.x, the SetParent function should be used to set

the parent of a window.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


More Information About Atoms

Article ID: Q12384

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following are questions on Atoms that expand on the description of

Atoms:

1. Q. Is it reasonable to use Atoms to store strings of data?

   A. Yes, you can store constant strings of data using Atoms.

2. Q. Why is there no Atom for a null string?

   A. There is no Atom for a null string because none is defined.

3. Q. How are Atoms stored?

   A. Atoms are hashed with bucket chaining used to resolve

      collisions. The memory for the Atoms is allocated out of the

      caller's DS. The overhead per Atom is 9 bytes (4 for the memory

      arena, 5 for the Atom structure).

4. Q. What is the penalty for declaring many Atoms and then only using

      a few?

   A. The only consequences of declaring many Atoms and then only

      using a few are the consumption of memory and the increased

      chain of collisions.

5. Q. Are there reasonable limits to the number of strings that can be

      stored as Atoms?

   A. The absolute limit to the number of strings that can be stored

      as Atoms is the size of the caller's data segment.

6. Q. Is there any way to share Atoms between two instances of a

      program?

   A. To share Atoms between two instances of a program, have a shared

      library .EXE file with a single data segment that holds the

      Atoms to be shared. The Windows user interface code is an

      example of this.

7. Q. Is there a limit to the number of characters in a string that is

      being stored as an Atom?

   A. The limit to the number of characters in a string being stored

      as an Atom currently is 255.

8. Q. Are Atoms movable?

   A. Atoms are constants, and therefore are not movable.

9. Q. Do Atoms get swapped?

   A. Atoms do not get swapped.

Additional reference words: 2.x 2.00 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMisc


Split Scrolling Using Two Windows

Article ID: Q19736

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

To create a window that has the following characteristics

 - a parent window that is a tiled window with both horizontal and

   vertical scroll bars

 - a child window that is a title, one line long, across the top of

   the parent window, and is stationary (that is, it does not scroll off

   the screen when the tiled window is scrolled vertically)

create two child windows:

 - The first should be one line

 - The second should be the rest of the client area

Then, perform all of the scrolling in the second child.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrPnt


Return Value from ChangeClipboardChain()

Article ID: Q28338

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The return value for ChangeClipboardChain() is TRUE if hWnd (the value

to be removed) is the last one on the chain. Otherwise, the value is

the return value [via SendMessage()] from the final item in the

Clipboard chain, which should be TRUE. The change can successfully be

made, however, even if the final window in the chain returns FALSE.

This merely indicates that the application with the final window in

the chain is handling the message incorrectly.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrClp


Scope of Window Classes

Article ID: Q28353

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article discusses the scope of window classes created by the

RegisterClass function and used by the CreateWindow function.

MORE INFORMATION

================

When an application calls the RegisterClass function, Windows

determines if that application has already registered a class with the

same name. If it has, registration fails because a module can register

only one class under a given name. When an application calls the

CreateWindow function to create a window of a specified class, Windows

looks in the list of registered classes for a class with the specified

class name registered by the calling module. If the class is not

found, Windows looks in the classes list for the specified class name

registered by any module. If the class name is not found, the call to

CreateWindow fails.

This implies that a module can create a window using any other

module's class if and only if it has not registered a class with the

same name. If a module registers a class with the same name as another

module's class, the module can use only its own version. However,

consider the following situation regarding the MyClass window class:

 - Application A and Application B each register window classes named

   MyClass.

 - Application C, which has not registered a MyClass window class,

   calls CreateWindow to create a MyClass-class window.

One cannot predict whether Windows will create the window using

Application A's MyClass class or Application B's MyClass class. To be

safe, the name of each window class should include the registering

application's name.

An application can reference a class defined by a dynamic-link library

(DLL). Under versions of Windows earlier than 3.1, an application should

not reference window classes registered by other applications. This

restriction is caused by the expanded memory manager (EMM) provided by

Windows real mode. Under certain conditions, the window procedure in

the module that registers a class is not available while the

application that created the window is running.

Additional reference words: 3.00 3.10

KBCategory: kbprgt

KBSubcategory: UsrCls


PRB: Window Dragged Close to Screen Edge Becomes Invisible

Article ID: Q31075

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

If the user uses the mouse to drag the left edge of a window (or

dialog box) within a few pixels of the right edge of the display

and releases the mouse button, the window moves completely off the

display. The user can't use the mouse to bring the window back

into the display.

CAUSE

=====

The window is created with the CS_BYTEALIGNCLIENT or

CS_BYTEALIGNWINDOW class style bit set. When the user releases the

mouse button, the window moves right to byte-align itself. However,

because the byte boundary is off the screen, the entire window

becomes invisible.

RESOLUTION

==========

There are two methods to work around this problem:

 - Give the window a system menu. This will prevent it from

   disappearing off the right edge of the screen.

   -or-

 - Calculate the size of any window that has a caption bar to

   conform to the following formula:

      horizontal_size modulo 8 <= 4

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrWndw


Changing the Mouse Cursor for a Window

Article ID: Q31747

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

There are two different methods that an application can use to change

the mouse cursor in a window:

 - The application can use the SetCursor function, which will change

   the mouse cursor immediately.

 - The application can use the SetClassWord function to change the

   mouse cursor for all windows of a particular window class. This

   method affects the mouse cursor only while it resides within the

   client area of a window of that class.

This article provides additional details regarding these two methods.

MORE INFORMATION

================

A number of factors should be considered during the design of an

application that changes the mouse cursor. The major consideration is

that Windows sends the WM_SETCURSOR message any time the mouse cursor

moves on the screen. Normally, Windows sends the message to the window

"under" the mouse cursor. However, if a window sets the mouse capture,

using the SetCapture function, that window receives all mouse

messages, without regard to the position of the mouse cursor.

When an application calls SetCursor, the mouse cursor changes to

reflect the cursor specified in the call. The cursor retains that

shape until SetCursor is called again, either explicitly by the

application, by the DefWindowProc function, or by another application.

Because Windows is a nonpreemptive multitasking environment, no other

application will gain control of the processor until the application

that has the processor releases it. If the application calls one of a

number of Windows functions, it can potentially lose control of the

processor. For a list of Windows functions that can cause control of

the processor to pass between applications, search on the following

words in the Microsoft Knowledge Base:

   prod(winsdk) and nonpreemptive and multitasking

When the DefWindowProc or DefDlgProc function processes a WM_SETCURSOR

message, it calls SetCursor to change the cursor to the default cursor

for the application's window.

The application can prevent the cursor from changing by processing the

WM_SETCURSOR message. A typical application that processes

WM_SETCURSOR will have a global variable for the handle to the current

cursor. When the application receives a WM_SETCURSOR message, it

checks the global variable. If the variable is NULL, the application

passes the WM_SETCURSOR message to DefWindowProc. Otherwise, the

application calls SetCursor with the value in the global variable. To

return the cursor to the window default cursor, set the global

variable to NULL.

When Windows sends a WM_SETCURSOR message, it places the hit-test area

code into the low-order word of the lParam parameter. The application

can use the hit-test area code to determine what particular portion of

the window is "under" the mouse cursor. For more information on the

hit-test area codes, see the documentation for the WM_NCHITTEST

message in the "Microsoft Windows Software Development Kit Reference

Volume 1."

Additional reference words: 3.00 3.10 RegisterClass

KBCategory: kbprg

KBSubcategory: UsrInp


Using the WM_CTLCOLOR Message

Article ID: Q32685

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

A WM_CTLCOLOR message is sent to a window each time one of its child window

controls (radio button, check box, scroll bar, and so forth) is to be

painted on the screen. This message precedes the painting of the control.

When it is desirable to change the appearance of controls, this can be done

by processing the WM_CTLCOLOR message.

MORE INFORMATION

================

When WM_CTLCOLOR is sent, wParam contains a handle to the display context

for the child window (in this case the control). The LOWORD of lParam

identifies the child window by its ID number, and the HIWORD of lParam

contains one of the following values, specifying the type of control that

is to be drawn:

   CTLCOLOR_BTN            button control

   CTLCOLOR_DLG            dialog box

   CTLCOLOR_EDIT           edit control

   CTLCOLOR_LISTBOX        list box

   CTLCOLOR_MSGBOX         message box

   CTLCOLOR_SCROLLBAR      scroll bar

   CTLCOLOR_STATIC         static text, frame, or rectangle

When WM_CTLCOLOR is processed, a handle to a brush must be returned.

Failure to return a brush handle will result in a Windows FatalExit on the

debugging monitor in the debug version of Windows.

DefWindowProc() already returns a handle in response to this message;

however, an application can return a different handle to customize the

color of controls. The handle that is returned specifies the brush to be

used to paint the control. For example, in Windows 2.x, the following code

paints the background of all buttons light gray:

        case WM_CTLCOLOR:

            if (HIWORD(lParam) == CTLCOLOR_BTN)

                return (GetStockObject(LTGRAY_BRUSH));

            return (GetStockObject(WHITE_BRUSH));

In this case, the backgrounds for all other controls are painted white.

Note that GetStockObject() returns a handle to the stock brush specified by

the parameter. To change the background color of a button control in

Windows 3.0 and later, it is necessary to create an owner draw button.

Returning a brush handle presents some interesting possibilities because

brush handles are not limited to those returned from GetStockObject().

Pattern brushes can be built from bitmaps. If a pattern brush handle is

returned in response to a WM_CTLCOLOR message, the brush would be used to

paint the background of controls.

The following code changes the painting of a scroll bar's thumb track area

to the basket-weave pattern found in Paint:

    /* Add these global variables. The array of WORDs specifies the */

    /* pattern for the brush                                        */

    HBRUSH  hBrush;

    HBITMAP hBitmap;

    WORD    wWeave[]={0x0F, 0x8B, 0xDD, 0xB8, 0x70, 0xE8, 0xDD, 0x8E};

     ...

    /* Add these lines to WinMain                                   */

    hBitmap = CreateBitmap(8, 8, 1, 1, (LPSTR)wWeave);

    hBrush = CreatePatternBrush(hBitmap);

     ...

   /* Add this case to the Windows procedure or wherever the       */

   /* messages are processed.                                      */

    case WM_CTLCOLOR:

        if (HIWORD(lParam) == CTLCOLOR_SCROLLBAR)

            return (hBrush);

        return (GetStockObject(WHITE_BRUSH));

The WM_CTLCOLOR message also applies to the following five classes of

controls:

1. Check boxes, radio buttons, and push buttons: Paints the

   rectangular area on which control is placed with selected brush;

   control shape and text is drawn over the painted pattern.

2. Edit control: Paints the editing area.

3. Group box: Paints the rectangular area behind the title text.

4. Scroll bars: Paints the area around the thumb track.

5. List box: Paints the listing area.

Static text, frames, and rectangles are unaffected by WM_CTLCOLOR.

NOTE: In Windows 3.0 and later, an application cannot change the color of a

button face. However, the user can use the Control Panel to change the

button colors for all applications in the system. This can also be

accomplished by modifying the [colors] section of the WIN.INI file to add a

"ButtonFace=" line that specifies the RGB color value for the button face

color.

Processing the WM_CTLCOLOR message only changes the color of child windows

created by an application. Windows sends the WM_CTLCOLOR message to the

parent window of each of these controls. Scroll bars that are included by

Windows as a part of edit controls or list boxes are not affected. The

thumb track area of system-generated scroll bars can only be changed in

WIN.INI or through the Control Panel.

It is also possible to paint the entire background of a dialog box.

The following code can be used to provide a dialog box color:

long FAR PASCAL MainWindowProc(....);

            ...

      case WM_CREATE:

         hTempBrush = LoadBitmap(hInst, (LPSTR)"MyPatternBrush");

         hBrush = CreatePatternBrush(hTempBrush);

         DeleteObject(hTempBrush);

            ...

      case WM_DESTROY:

         DeleteObject(hBrush);

            ...

BOOL FAR PASCAL MyDialogProc(....);

            ...

      case WM_CTLCOLOR:

         if (bMonoChrome)

            return (FALSE);   // Do nothing if on a monochrome monitor

                              // bMonoChrome is a global set during

                              // initialization.

         if (CTLCOLOR_DLG == HIWORD(lParam))

            UnrealizeObject(hBrush);

         SelectObject((HDC)wParam, hBrush);

         if (CTLCOLOR_DLG == HIWORD(lParam))

            SetBrushOrg((HDC)wParam, 0, 0);

         SetBkMode((HDC)wParam, TRANSPARENT);

         SetTextColor((HDC)wParam, RGB(0, 0, 0));

         return(hBrush);

            ...

This code will ensure that a patterned bitmap will line up correctly

across the entire dialog box. "MyPatternBrush" is the name of a bitmap

created using SDKPaint. This bitmap must be included in the .RC file.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrPnt


Obtaining an Application's Instance Handle

Article ID: Q35767

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Many Windows API functions require an application's instance handle as

a parameter. This article describes three methods that an application

can use to obtain its instance handle.

MORE INFORMATION

================

Depending on the situation, an application might use any of the

following three methods to obtain its instance handle:

1. The hInstance parameter to the WinMain procedure is the

   application's instance handle. The application can save this value

   in a global variable, making it available throughout the application.

2. The lParam parameter of the WM_CREATE message points to a

   CREATESTRUCT data structure, and the hInstance field of this

   structure is the application's instance handle. During the

   processing of the WM_CREATE message a window procedure can save

   this value in a static variable, as follows:

      hInst = ((LPCREATESTRUCT)lParam)->hInstance;

   This variable would then be available during all subsequent calls

   to the window procedure.

3. Given a window handle for one of its windows, an application can

   obtain its instance handle by calling the GetWindowWord function:

      GetWindowWord(hWnd, GWW_HINSTANCE)

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Differences Between PostAppMessage and PostMessage Funcs

Article ID: Q35774

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The following information describes the differences between the

PostAppMessage and PostMessage functions, and the circumstances under

which each should be used.

MORE INFORMATION

================

In most cases, the PostMessage function should be used. Essentially,

both functions accomplish the same result, but PostMessage uses a

window handle, and PostAppMessage uses a task handle to identify the

destination window for the message.

In the Windows environment, it is possible to create a task that does

not have a window associated with it, but not vice versa. Under some

circumstances an application must send a message to a windowless

application; there is no window handle to use as a parameter to

PostMessage. In this case, use the PostAppMessage function to send the

message using the task handle.

However, if an application will receive messages sent by

PostAppMessage, its message loop must be modified. When a message is

posted by PostAppMessage and retrieved by GetMessage, the hwnd field

of the MSG structure is NULL because no window was specified as the

target for the message. Therefore, it is important to process this

special case and to perform whatever processing is appropriate. An

application must not pass an MSG structure with a NULL hwnd field to

the DispatchMessage function. Doing so will cause an error. Some

possibilities for handling this special case are listed below:

 - Process the message within the message loop.

 - Pass the message to another procedure that is set up to process

   special cases.

 - Set the hwnd field of the MSG structure to the window handle of the

   window that should receive the message.

 - Change any of the other values in the MSG structure before passing

   the message along.

The following code demonstrates processing a message posted by the

PostAppMessage function. After the window is drawn, pressing the left

mouse button in the window generates a PostMessage call, and pressing

the right mouse button generates an identical PostAppMessage call.

When the application processes the message posted by PostAppMessage,

it beeps the speaker and then passes the message to the main window.

//*******************************************************************

// MinWin - PostMessage versus PostAppMessage example.

#include <windows.h>

char szAppName[] = "MinWin";

HWND hMainWnd;

long FAR PASCAL WndProc(HWND, unsigned, WORD, LONG);

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,

                   LPSTR lpszCmdLine, int nCmdShow)

{

   MSG msg;

   WNDCLASS wndclass;

   if (!hPrevInstance)

      {

      wndclass.style = CS_HREDRAW | CS_VREDRAW;

      wndclass.lpfnWndProc = WndProc;

      wndclass.cbClsExtra = 0;

      wndclass.cbWndExtra = 0;

      wndclass.hInstance = hInstance;

      wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

      wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

      wndclass.hbrBackground = COLOR_WINDOW + 1;

      wndclass.lpszMenuName = NULL;

      wndclass.lpszClassName = szAppName;

      if (!RegisterClass(&wndclass))

         return FALSE;

      }

   hMainWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW,

        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,

        NULL, NULL, hInstance, NULL);

   ShowWindow(hMainWnd, nCmdShow);

   UpdateWindow(hMainWnd);

   while (GetMessage(&msg, NULL, 0, 0))

      {

      if (msg.hwnd == NULL) // Beep, then pass the message to

         {                  //  the window

         MessageBeep(0);

         msg.hwnd = hMainWnd;

         }

      TranslateMessage(&msg);

      DispatchMessage(&msg);

      }

   return msg.wParam;

}

long FAR PASCAL WndProc(HWND hWnd, unsigned iMessage,

                        WORD wParam, LONG lParam)

{

   HANDLE hInst;

   HANDLE hTask;

   hInst = GetWindowWord(hWnd, GWW_HINSTANCE);

   switch (iMessage)

      {

   case WM_LBUTTONDOWN:

      PostMessage(hWnd, WM_USER+0x1000, 0, 0L);

      break;

   case WM_RBUTTONDOWN:

      PostAppMessage(GetWindowTask(hWnd), WM_USER+0x1000, 0, 0L);

      break;

   case WM_USER+0x1000:

      MessageBox(NULL, "Message Received", "WM_USER", MB_OK);

      break;

   case WM_DESTROY:

      if (hWnd == hMainWnd)

         PostQuitMessage(0);

      break;

   default:

      return DefWindowProc(hWnd, iMessage, wParam, lParam);

      }

   return 0L;

}

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMsg


Active Application, Active Window, Input Focus Definition

Article ID: Q35957

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Although the concepts of "input focus," "active application," and

"active window" are very closely related, there are differences among

them.

1. The "input focus" determines which window receives keyboard input.

2. The "active window" is the window that receives the user's

   attention. If it's an overlapped window or a pop-up window with a

   caption bar, the caption bar is highlighted. If it's a dialog

   window, the frame is highlighted. Either the active window or one

   of its child windows has the focus.

3. The "active application" is the application that created the window

   that has the input focus.

MORE INFORMATION

================

The following discussion contains detailed definitions of the terms

"input focus," "active window," and "active application," as well as a

demonstration of those differences that you can perform using Windows

Write.

The following definition is from the glossary of "Programmer's Guide

to Windows, Second Edition," by David Durant, Geta Carlson, and Paul

Yao, published by Sybex, page 647:

   Active Application

   The active application is the application that created the window

   that currently has the keyboard input focus. Applications do not

   need to be the active application in order to receive and process

   messages. Applications are notified by message whenever they are

   gaining or losing the status of "the active application." The user

   normally determines the active application, but applications can

   override this decision.

For more information on the active application, refer to the

documentation for the WM_ACTIVATEAPP message in the "Microsoft Windows

Software Development Kit (SDK) Reference, Volume 1."

The following is also from "Programmer's Guide to Windows, Second

Edition," page 655:

   Focus

   Keyboard input is transferred to the application as messages. Since

   several windows may be visible on the screen simultaneously, there

   must be a method for determining which of these windows should

   receive the keyboard input messages. In Windows, the window that

   has the focus is the window that will receive the keyboard

   messages. Normally, the user controls which window has the focus by

   use of the mouse, but applications can transfer the focus from

   window to window themselves.

For more information on focus, refer to the documentation for the

WM_SETFOCUS and WM_KILLFOCUS messages and for the GetFocus, SetFocus,

and EnableWindow functions in the "SDK Reference, Volume 1."

The following is from the book Programming Windows, Second Edition by

Charles Petzold, published by Microsoft Press, pages 89-90:

   Focus, Focus, Who's Got the Focus?

   The keyboard must be shared by all applications running under

   Windows. Some applications may have more than one window, and the

   keyboard must be shared by these windows within the same

   application. When a key on the keyboard is pressed, only one window

   procedure can receive a message that the key has been pressed. The

   window that receives this keyboard message is the window with the

   "input focus."

   The concept of input focus is closely related to the concept of

   "active window." The window with the input focus is either the

   active window or a child window of the active window. The active

   window is usually easy to identify. If the active window has a

   caption bar, Windows highlights the caption bar. If the active

   window has a dialog frame (a form most commonly seen in dialog

   boxes) instead of a caption bar, Windows highlights the frame. If

   the active window is an icon, Windows highlights the window's

   caption bar text below the icon.

   The most common child windows are controls such as push buttons,

   radio buttons, check boxes, scroll bars, edit boxes, and list boxes

   that usually appear in a dialog box. Child windows are never

   themselves active windows. If a child window has the input focus,

   then the active window is its parent. Child window controls

   indicate that they have the input focus generally by using a

   flashing cursor or caret.

   If the active window is an icon, then no window has the input

   focus. Windows continues to send keyboard messages to the icon, but

   these messages are in a different form from keyboard messages sent

   to active windows that are not icons.

   A window procedure can determine when it has the input focus by

   trapping WM_SETFOCUS and WM_KILLFOCUS messages. WM_SETFOCUS

   indicates that the window is receiving the input focus, and

   WM_KILLFOCUS signals that the window is losing the input focus.

Petzold also indicates that Windows sends keyboard messages to icons

differently than it does to windows with the focus. This difference is

noted in the following excerpt from the "Microsoft Windows Software

Development Kit Reference, Volume 1," page 4-381:

   If a window is active but doesn't have the focus (that is, no

   window has the focus), any key pressed will produce the WM_SYSCHAR,

   WM_SYSKEYDOWN, or WM_SYSKEYUP message.

For more information on the active window, refer to the documentation

for the WM_ACTIVATE message and for the GetActiveWindow and

SetActiveWindow functions in the "Microsoft Windows Software

Development Kit Reference, Volume 1."

Demonstration of Differences Between

Focus, Active Application, and Active Window

--------------------------------------------

The following is an experiment you can do that will clarify the

differences among active application, active window, and input focus,

and show you how the user can specify which attribute is assigned to

which window:

Open Windows Write and choose Find from the Find menu. You'll now have

a pop-up window that is a child of Write. Arrange your screen so that

the Write, Find, and Program Manager windows are all on the screen

together.

If you click in the Program Manager window, both the Write window's

and the Find dialog window's caption bars will be set to the inactive

color, and the Program Manager window's caption bar will be set to the

active color. At this point, Program Manager is the active

application; it is also the active window and has the input focus.

Click in the Write window; it will become the active application, as

well as the active window, and will get the input focus.

Click in the Find window; although it is now the active window, it is

not the active application (Write is) nor does it have the input

focus: the focus is in the Find What box, which is an edit control

window that is a child of the Find dialog window, which is itself a

pop-up-style window that is a child of Write. (Note that in this

discussion the term "child windows" is used in terms of parent-child

relationships rather than the child window style WS_CHILD.)

At this point, you can move the input focus from box to box within the

Find dialog window by using the TAB key (or by clicking with the

mouse). There are three or four controls you can move between: Find

What, Whole Word, Match Upper/Lowercase, and Find Next (available only

if there is some text in the Find What box).

Now press ALT+F6. This will make Write the active window instead of

Find, and the focus will be set to the Write window as well; this is

indicated by the flashing vertical caret. Press ALT+F6 a second time.

Find will be the active window again, and the input focus will be set

to whichever control it was last set to (Find What, Whole Word, Match

Upper/Lowercase, or Find Next).

Finally, you can use ALT+TAB to return to the Program Manager, making

it the active application, the active window, and the one with the

input focus. If you press ALT+TAB again, you will make Write the

active application, Find the active window, and set the input focus to

one of Find's controls (whichever one last had the focus).

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Algorithm Creates Window Same Size As Full-Screen Window

Article ID: Q36319

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The algorithm listed below creates a window the size of the "standard"

full-screen window.

MORE INFORMATION

================

    int winBorder, cxBorder, cyBorder,

        cxMargin, cxBAMargin, cyBAMargin,

        x, y, cx, cy;

    /* Get the user-defined border width */

    winBorder = GetProfileInt("windows", "BorderWidth", 5);

    /* It must be in the range of 0 < winBorder < 51 */

    if (winBorder < 1) {

        winBorder = 1;

    } else if (winBorder > 50) {

        winBorder = 50;

    }

    /* Get some internal system metrics to determine extra scaling */

    cxBorder = GetSystemMetrics (SM_CXBORDER);

    cyBorder = GetSystemMetrics (SM_CYBORDER);

    cxMargin = (cxBorder * winBorder) + cxBorder;

    /* Byte align the border */

    cxBAMargin = (((cxMargin + 7) & 0xFFF8) - cxMargin);

    cyBAMargin = cxBAMargin * cyBorder / cxBorder;

    x  = cxBAMargin;

    y  = cyBAMargin;

    cx = CW_USEDEFAULT;

    cy = 0;

    hWnd = CreateWindow(szAppName, szTitle, WS_OVERLAPPEDWINDOW,

                        x, y, cx, cy,

                        NULL, NULL, hInstance, NULL);

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Performing Background Processing Without Using Timers

Article ID: Q36324

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

A Windows-based application that performs a long, background task, such as

repaginating a word processing document, can be designed in a number

of different ways.

A polling task can be accomplished by setting a timer to fire at the

desired interval. Many nonpolling tasks can be performed in pieces.

Although Windows does not have a method to schedule processing based

on overall system load, an application can wait until there are no

other messages to be processed by that application before proceeding.

This article discusses the code required to implement this method.

NOTE: This polling method is unneccesary for native Win32 applications.

MORE INFORMATION

================

It is important that each piece of the task be relatively small. This

allows Windows to devote processing time to other applications running

in the system. Similarly, once the task is complete, it is important

that the application signal that it is idle. This allows Windows to

optimize its performance and to prolong battery life on portable

computers.

The following code skeleton demonstrates how this might be

implemented:

WinMain

{

do application initialization

fBackgroundToDo = TRUE;

fRunning = TRUE;

while (fBackgroundToDo && fRunning)

     {

     if (fBackgroundToDo)

          {

          if ((PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

               {

               if (msg.message == WM_QUIT)

                    {

                    fRunning = FALSE;

                    break;

                    }

               TranslateMessage(&msg);

               DispatchMessage(&msg);

               }

          else

               fBackgroundToDo = DoABitOfBackground();

          }

     else if ((fRunning = GetMessage(&msg, NULL, NULL, NULL)) != 0)

          {

          TranslateMessage(&msg);

          DispatchMessage(&msg);

          fBackgroundToDo = IsThereBackgroundToDo();

          }

     }

}

For additional information on this topic, query on the following words in

this Knowledge Base:

   SpawnAndWait

Additional reference words: 3.00 3.10 multitask

KBCategory: kbprg

KBSubcategory: UsrMsg


When PostMessage() Will Return 0, Indicating Failure

Article ID: Q36584

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

PostMessage(hWnd,wMsg,wParam,lParam) returns 0, indicating failure,

for one of the following two reasons:

1. The window handle (hWnd parameter to PostMessage()) receiving the

   message is -1. If this is the case, the message (wMsg) is broadcast

   to all windows.

2. The window to receive the message has a full application queue.

Note that PostMessage() does not return NULL if the hWnd parameter in

the PostMessage() call is an invalid window handle. Also note that

IsWindow() can be called to verify whether a given handle is indeed a

valid window handle.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrMsg


DlgDirSelect() Has Undocumented Behavior

Article ID: Q36917

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

If you use DlgDirSelect() to get the selection from a list box and

there is no selection, DlgDirSelect() returns zero and leaves the

output string unchanged.

Clicking in the white space after the last item in a list box is one

reason there may not be a selection.

Because DlgDirSelect() returns 0 (zero) when the selection is a file

and 0 when there is no selection at all, using the return value alone

is not enough to determine if there is a current selection. One way to

determine if there is a selection is to send the LB_GETCURSEL message

to the list box. If the return value is not LB_ERR from this message,

there currently is a selected item in the list box.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


Limit to the Number of Characters Stored in a List Box

Article ID: Q39544

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The memory limit for a Windows list box depends strictly on the number

of characters, not on the number of items in the list box. The memory

for the strings is allocated from global memory, but the internal code

assumes that the total amount of memory required by the strings in the

list box will not exceed 32K (in Windows versions 2.x). If the total

memory required by the strings is more than 32K, the list box will not

function correctly.

Under Windows version 3.0, the limit is 64K of text.

Additional reference words: 3.00 3.10 listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Communicating Between Windows Virtual Machines with DDE

Article ID: Q40620

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 adn 3.1

----------------------------------------------------------------------

Windows 286 supported DDE (dynamic data exchange) for MS-DOS (non-Windows)

applications; however, Windows/386 and Windows versions 3.x do not include

this functionality.  There are no plans to add this functionality in future

versions of Windows.

The following are methods descrive several different ways for an MS-DOS-

based application to communicate with a Windows-based application:

1. The Clipboard. MS-DOS-based applications can read from or write to the

   Clipboard. The methods for doing this are documented in the Windows

   SDK (Software Development Kit). Microsoft Word incorporates this

   capability. This is the preferred method of communication.

2.  A shared file. To improve performance, SMARTDRV or a RAM disk can be

   used. SHARE.EXE should be loaded before starting Windows to allow for

   proper file sharing and locking

3. MS-DOS TSR (terminate-and-stay-resident) program. Another method that

   can be used is to start an MS-DOS TSR program with a buffer at a fixed

   location that can be read/written to by different applications. For

   this method to work, the memory region used must be below the load

   point of Windows 3.x, otherwise the different virtual machines will

   have their own private copies of the address space.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


FatalExit 0x0001 Possible If WM_CTLCOLOR Used Improperly

Article ID: Q42458

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

An application can change the colors of a dialog box by creating a

brush of the desired color and processing the WM_CTLCOLOR message to

return a handle to the brush. If the brush is not a stock object, the

application should create the brush before the dialog box is displayed

and store its handle in a global or static variable. Do not use the

following code in a dialog box procedure:

   case WM_CTLCOLOR:  // Create green edit fields

      if (HIWORD(lParam) == CTLCOLOR_EDIT)

         return CreateSolidBrush(RGB(0, 255, 0));

      break;

Windows sends a WM_CTLCOLOR message to the dialog box procedure each

time any changes are made to the dialog box (such as when the user

presses a button or moves the focus to a new control). In the code

above, each time the application processes a WM_CTLCOLOR message for

an edit control, the application creates a new brush which is stored

in the GDI data segment. If the GDI data segment fills completely,

Windows generates a FatalExit 0x0001 (insufficient memory for

allocation) error for each subsequent allocation.

MORE INFORMATION

================

To avoid this error, modify the application to call the

CreateSolidBrush function once, either outside the application's

message loop or during the processing of the WM_CREATE message. Store

the returned brush handle in a global or static variable. An advantage

of this method is that the brush can be used in any part of the

application without consuming any additional system resources.

The following code provides a skeleton for the WinMain procedure and

for the dialog procedure to implement this method:

// WinMain

HBRUSH  hBrushGreen; // Global variable

WinMain (...)

{

   // Register window class and create window

   hBrushGreen = CreateSolidBrush(RGB(0, 255, 0));

   while (GetMessage(...))

     {

     TranslateMessage(...);

     DispatchMessage(...);

     }

   DeleteObject(hBrushGreen);

   return msg.wparam;

}

// Dialog box procedure

   case WM_CTLCOLOR: // Green edit fields

      if (HIWORD(lParam) == CTLCOLOR_EDIT)

         return hBrushGreen;

      break;

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


General Information About Windows WM_TIMER Messages

Article ID: Q44740

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Timers in the Windows environment are not synchronous; that is, when a

timer "goes off," Windows does not stop processing and send a WM_TIMER

message or call the timer event procedure. Instead, Windows sets some

bits internally, to ensure that the task that "owns" the timer will

run (as soon as the current task does something to yield control).

When this task does eventually run and eventually calls GetMessage()

or PeekMessage(), and there are no other messages available for this

task, Windows will scan the timer list to see if any timers for this

task have "gone off." If they have, Windows returns a WM_TIMER message

or calls the timer event procedure. The following are two important

facts that must be considered:

1. The WM_TIMER message and timer-event process ONLY happen when an

   application is sitting on a GetMessage() or PeekMessage(). They do

   not happen at timer interrupt time.

2. Only timers for the task that is currently active are scanned when

   looking for messages. A PARTICULAR TIMER IS OWNED BY THE TASK THAT

   WAS ACTIVE WHEN THE TIMER WAS CREATED.

MORE INFORMATION

================

The following is an example of the incorrect use of timers:

An application sets a keyboard hook. Inside the keyboard hook, a timer

is set. It is important to realize that the keyboard hook is called

from within GetMessage() or PeekMessage() whenever a task is pulling

keys out of the system queue (the place where keyboard and mouse

events go at interrupt level). The task that is active at the time the

keyboard hook is called is completely random. Basically, it is the

task that owns the windows with the focus.

Because a timer is owned by the active task at the time it is created,

and any task may be the active task when the keyboard hook is called,

the timer created in this manner will be owned by some random task.

This, combined with the following facts, results in inconsistent,

random behavior for this timer.

1. Timers are only scanned for the active task.

2. Timers are retrieved at message level.

3. All applications handle messages differently.

The basic rule is that a timer MUST NEVER be created from within a

hook such as a keyboard hook.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrTim


Calculating Free System Resources in Microsoft Windows

Article ID: Q61803

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, the About dialog box

in the Program Manager displays a value that indicates the amount of

free system resources available at a given time. The text below

documents this calculation and the methods that an application can use

to calculate this figure.

MORE INFORMATION

================

Windows uses the same method to calculate the percentage of free

system resources in each of its operating modes (real mode, standard

mode, and enhanced mode under Windows 3.0, and standard mode and

enhanced mode under Windows 3.1).

In the Windows environment, system resources are the amount of space

available in the data segment (DS) for the user dynamic-link library

(DLL) or the GDI DLL. Because system resources are exhausted if either

of these data segments fills up, Windows reports the smaller of the

two percentages for the system. The following formula describes the

calculation for Windows 3.0 and 3.1; this may or may not be accurate

in future versions of Windows:

   % free = min (% free of user DS, % free of GDI DS)

               (64K - current DS size) + free blocks in Heap

   % free DS = --------------------------------------------- * 100

                     64K - (size of statics and stack)

Or, in other words:

                 Current free heap assuming 64K

   % free DS =  -------------------------------- * 100

                   Maximum heap assuming 64K

Under Windows 3.1, an application can call the GetFreeSystemResouces

function with the GFSR_SYSTEMRESOURCES value to obtain the percentage

of free system resources. Because this function is not present in

Windows 3.0, an application that runs in both environments must

explicitly import this function from the user dynamic-link library

(DLL) when the application runs under Windows 3.1.

Under Windows 3.0, an application can use the GetHeapSpaces function

to determine the percentage of free system resources as follows:

   DWORD cbFree;

   WORD  wFreeK, wHeapK;

   WORD  wUserPercent, wGDIPercent, wSysPercent;

   cbFree = GetHeapSpaces(GetModuleHandle("USER"));

   wFreeK = LOWORD(cbFree) / 1024;

   wHeapK = HIWORD(cbFree) / 1024;

   wUserPercent = MulDiv(wFreeK, 100, wHeapK);

   cbFree = GetHeapSpaces(GetModuleHandle("GDI"));

   wFreeK = LOWORD(cbFree) / 1024;

   wHeapK = HIWORD(cbFree) / 1024;

   wGDIPercent = MulDiv(wFreeK, 100, wHeapK);

   wSysPercent = min(wUserPercent, wGDIPercent);

Because this technique does not provide accurate results under Windows

3.1, an application must determine the version of Windows with which

it is running and perform the calculation accordingly.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrSys


Do Not Call Message Boxes Via Radio Buttons

Article ID: Q62741

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When programming calls to MessageBox() in response to dialog box

controls, you may observe the following phenomenon.

An application-modal message box that is opened within the processing

logic for a radio button control crashes the system (you keep getting

message boxes until USER runs out of local heap space). There is no

problem as soon as you replace the radio button style by a push button

style.

Although this is a problem in Windows, there should not really be a

need to use this feature at all. Radio buttons are designed to be a

mechanism to choose between mutually exclusive options (for more

information, refer to the CUA style guide). Opening a message box as a

direct response to the selection of a radio button is not a preferred

programming technique. If the selected option raises some kind of

error, the radio button can always be disabled using the

EnableWindow() function.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Windows Message-Processing Caveats

Article ID: Q64329

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Do not call any function that may cause control to yield to another

application during the processing of any of the following messages:

   WM_ACTIVATE

   WM_ACTIVATEAPP

   WM_CREATE

   WM_INITDIALOG

   WM_NCCREATE

Certain messages are used to notify applications of some change in

Windows's internal status. While processing one of these messages, an

application cannot call any function that may result in control being

yielded to another application. Forbidden functions include

message-processing functions such as MessageBox(), DialogBox(),

GetMessage(), and PeekMessage().

Violating this caveat may cause Windows to exhibit strange visual

behavior.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


Using WriteProfileString to Delete WIN.INI Entries

Article ID: Q65111

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The WriteProfileString function provides a mechanism to maintain the

system profile file WIN.INI. In versions of Windows prior to version

3.0, an application could call the WriteProfileString function to add

entries to WIN.INI or to modify existing entries. However, to delete

an entry from WIN.INI, the user was required to edit the file

manually.

The WriteProfileString function was extended in Windows 3.0 to enable

an application to delete any of the following from WIN.INI:

1. A value associated with a key name.

2. A line that contains a particular key name.

3. An entire section.

This article details the three deletion scenarios listed above.

MORE INFORMATION

================

The parameters passed to the WriteProfileString function refer to the

following selection from an example WIN.INI file:

   [MY_APP]

   KeyName = DATA

To delete the line KeyName = DATA, call the WriteProfileString

function as follows:

   WriteProfileString("MY_APP", "KeyName", NULL);

To delete the value DATA, change the call to the following:

   WriteProfileString("MY_APP", "KeyName", "");

To delete the entire MY_APP section, make the following call:

   WriteProfileString("MY_APP", NULL, NULL);

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrIni


Executable-File Header Format

Article ID: Q65122

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

NOTE: This article is part of a set of seven articles, collectively

called the "Windows 3.00 Developer's Notes." More information about

the contents of the other articles, and procedures for ordering a

hard-copy set, can be found in the Microsoft Knowledge Base article:

   ARTICLE-ID: Q65260

   TITLE     : The Windows 3.00 Developer's Notes

Download EXEFMT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EXEFMT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EXEFMT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EXEFMT.EXE

MORE INFORMATION

================

Microsoft defined the segmented executable file format for Windows

applications and dynamic-link libraries (DLLs). This file format is also

referred to as the New Executable Format. This new format is an extension

of the existing MS-DOS .EXE format (old-style format). The purpose of the

segmented executable format is to provide the information needed to support

the dynamic linking and segmentation capabilities of the Windows

environment.

An executable file contains Microsoft Windows code and data, or Windows

code, data, and resources. Specific fields have been added to the old-style

.EXE format header to indicate the existence of the segmented file format.

The old-style header may contain a valid executable program, called a stub

program, that will be executed if the program is run on MS-DOS (without

Windows). This stub program usually prints a message indicating that

Microsoft Windows is required to run the program. The segmented executable

format extensions also begin with a header that describes the contents and

location of the executable image in the file. The loader uses this header

information when it loads the executable segments in memory.

======================================================================

                     OLD-STYLE HEADER EXTENSIONS

======================================================================

The old-style header contains information the loader expects for an MS-DOS

executable file. It describes a stub program (WINSTUB) the loader can

place in memory when necessary, it points to the new-style header, and

it contains the stub programs relocation table.

The following illustrates the distinct parts of the old-style

executable format:

        +-------------------------+

    00h |  Old-style header info  |

        +-------------------------+

    20h |        Reserved         |

        +-------------------------+

    3Ch |   Offset to segmented   |

        |       .EXE header       |

        +-------------------------+

    40h |  Relocation table and   |

        |  MS-DOS stub program    |

        +-------------------------+

        |  Segmented .EXE Header  |

        |           .             |

        |           .             |

        |           .             |

The word at offset 18h in the old-style .EXE header contains the

relative byte offset to the stub program's relocation table. If this

offset is 40h, then the double word at offset 3Ch is assumed to be the

relative byte offset from the beginning of the file to the beginning

of the segmented executable header. A new-format .EXE file is

identified if the segmented executable header contains a valid

signature. If the signature is not valid, the file is assumed to be an

old-style format .EXE file. The remainder of the old-style format

header will describe an MS-DOS program, the stub. The stub may be any

valid program but will typically be a program that displays an error

message.

======================================================================

                         SEGMENTED EXE FORMAT

======================================================================

Because Windows executable files are often larger than one segment

(64K), additional information (that does not appear in the old-style

header) is required so that the loader can load each segment properly.

The segmented EXE format was developed to provide the loader with this

information.

The segmented .EXE file has the following format:

        +-----------------+

    00h |  Old-style EXE  |

        |      Header     |

        +-----------------+

    20h |    Reserved     |

        +-----------------+

    3Ch |    Offset to    | ---+

        | Segmented Header|    |

        +-----------------+    |

    40h | Relocation Table|    |

        |  & Stub Program |    |

        +-----------------+    |

        |                 |    |

        +-----------------+    |

    xxh |  Segmented EXE  | <--+

        |      Header     |

        +-----------------+

        |  Segment Table  |

        +-----------------+

        | Resource Table  |

        +-----------------+

        |  Resident Name  |

        |      Table      |

        +-----------------+

        | Module Reference|

        |      Table      |

        +-----------------+

        | Imported Names  |

        |      Table      |

        +-----------------+

        |   Entry Table   |

        +-----------------+

        |  Non-Resident   |

        |   Name Table    |

        +-----------------+

        |   Seg #1 Data   |

        |   Seg #1 Info   |

        +-----------------+

                .

                .

                .

        +-----------------+

        |   Seg #n Data   |

        |   Seg #n Info   |

        +-----------------+

The following sections describe each of the components that make up

the segmented EXE format. Each section contains a description of the

component and the fields in the structures that make up that

component.

NOTE: All unused fields and flag bits are reserved for future use and

must contain 0 (zero) values.

======================================================================

                         SEGMENTED EXE HEADER

======================================================================

The segmented EXE header contains general information about the EXE

file and contains information on the location and size of the other

sections. The Windows loader copies this section, along with other

data, into the module table in the system data. The module table is

internal data used by the loader to manage the loaded executable

modules in the system and to support dynamic linking.

The following describes the format of the segmented executable header.

For each field, the offset is given relative to the beginning of the

segmented header, the size of the field is defined, and a description

is given.

    Offset Size Description

    ------ ---- -----------

    00h     DW  Signature word.

                "N" is low-order byte.

                "E" is high-order byte.

    02h     DB  Version number of the linker.

    03h     DB  Revision number of the linker.

    04h     DW  Entry Table file offset, relative to the beginning of

                the segmented EXE header.

    06h     DW  Number of bytes in the entry table.

    08h     DD  32-bit CRC of entire contents of file.

                These words are taken as 00 during the calculation.

    0Ch     DW  Flag word.

                0000h = NOAUTODATA

                0001h = SINGLEDATA (Shared automatic data segment)

                0002h = MULTIPLEDATA (Instanced automatic data

                        segment)

                2000h = Errors detected at link time, module will not

                        load.

                8000h = Library module.

                        The SS:SP information is invalid, CS:IP points

                        to an initialization procedure that is called

                        with AX equal to the module handle. This

                        initialization procedure must perform a far

                        return to the caller, with AX not equal to

                        zero to indicate success, or AX equal to zero

                        to indicate failure to initialize. DS is set

                        to the library's data segment if the

                        SINGLEDATA flag is set. Otherwise, DS is set

                        to the caller's data segment.

                        A program or DLL can only contain dynamic

                        links to executable files that have this

                        library module flag set. One program cannot

                        dynamic-link to another program.

    0Eh     DW  Segment number of automatic data segment.

                This value is set to zero if SINGLEDATA and

                MULTIPLEDATA flag bits are clear, NOAUTODATA is

                indicated in the flags word.

                A Segment number is an index into the module's segment

                table. The first entry in the segment table is segment

                number 1.

    10h     DW  Initial size, in bytes, of dynamic heap added to the

                data segment. This value is zero if no initial local

                heap is allocated.

    12h     DW  Initial size, in bytes, of stack added to the data

                segment. This value is zero to indicate no initial

                stack allocation, or when SS is not equal to DS.

    14h     DD  Segment number:offset of CS:IP.

    18h     DD  Segment number:offset of SS:SP.

                If SS equals the automatic data segment and SP equals

                zero, the stack pointer is set to the top of the

                automatic data segment just below the additional heap

                area.

                    +--------------------------+

                    | additional dynamic heap  |

                    +--------------------------+ <- SP

                    |    additional stack      |

                    +--------------------------+

                    | loaded auto data segment |

                    +--------------------------+ <- DS, SS

    1Ch     DW  Number of entries in the Segment Table.

    1Eh     DW  Number of entries in the Module Reference Table.

    20h     DW  Number of bytes in the Non-Resident Name Table.

    22h     DW  Segment Table file offset, relative to the beginning

                of the segmented EXE header.

    24h     DW  Resource Table file offset, relative to the beginning

                of the segmented EXE header.

    26h     DW  Resident Name Table file offset, relative to the

                beginning of the segmented EXE header.

    28h     DW  Module Reference Table file offset, relative to the

                beginning of the segmented EXE header.

    2Ah     DW  Imported Names Table file offset, relative to the

                beginning of the segmented EXE header.

    2Ch     DD  Non-Resident Name Table offset, relative to the

                beginning of the file.

    30h     DW  Number of movable entries in the Entry Table.

    32h     DW  Logical sector alignment shift count, log(base 2) of

                the segment sector size (default 9).

    34h     DW  Number of resource entries.

    36h     DB  Executable type, used by loader.

                  02h = WINDOWS

    37h-3Fh DB  Reserved, currently 0's.

======================================================================

                            SEGMENT TABLE

======================================================================

The segment table contains an entry for each segment in the executable

file. The number of segment table entries are defined in the segmented

EXE header. The first entry in the segment table is segment number 1.

The following is the structure of a segment table entry.

   Size Description

   ---- -----------

   DW   Logical-sector offset (n byte) to the contents of the segment

        data, relative to the beginning of the file. Zero means no

        file data.

   DW   Length of the segment in the file, in bytes. Zero means 64K.

   DW   Flag word.

        0007h = TYPE_MASK  Segment-type field.

        0000h = CODE       Code-segment type.

        0001h = DATA       Data-segment type.

        0010h = MOVEABLE   Segment is not fixed.

        0040h = PRELOAD    Segment will be preloaded; read-only if

                           this is a data segment.

        0100h = RELOCINFO  Set if segment has relocation records.

        F000h = DISCARD    Discard priority.

   DW   Minimum allocation size of the segment, in bytes. Total size

        of the segment. Zero means 64K.

======================================================================

                            RESOURCE TABLE

======================================================================

The resource table follows the segment table and contains entries for

each resource in the executable file. The resource table consists of

an alignment shift count, followed by a table of resource records. The

resource records define the type ID for a set of resources. Each

resource record contains a table of resource entries of the defined

type. The resource entry defines the resource ID or name ID for the

resource. It also defines the location and size of the resource. The

following describes the contents of each of these structures:

   Size Description

   ---- -----------

   DW   Alignment shift count for resource data.

   A table of resource type information blocks follows. The following

   is the format of each type information block:

        DW  Type ID. This is an integer type if the high-order bit is

            set (8000h); otherwise, it is an offset to the type string,

            the offset is relative to the beginning of the resource

            table. A zero type ID marks the end of the resource type

            information blocks.

        DW  Number of resources for this type.

        DD  Reserved.

        A table of resources for this type follows. The following is

        the format of each resource (8 bytes each):

            DW  File offset to the contents of the resource data,

                relative to beginning of file. The offset is in terms

                of the alignment shift count value specified at

                beginning of the resource table.

            DW  Length of the resource in the file (in bytes).

            DW  Flag word.

                0010h = MOVEABLE  Resource is not fixed.

                0020h = PURE      Resource can be shared.

                0040h = PRELOAD   Resource is preloaded.

            DW  Resource ID. This is an integer type if the high-order

                bit is set (8000h), otherwise it is the offset to the

                resource string, the offset is relative to the

                beginning of the resource table.

            DD  Reserved.

   Resource type and name strings are stored at the end of the

   resource table. Note that these strings are NOT null terminated and

   are case sensitive.

   DB   Length of the type or name string that follows. A zero value

        indicates the end of the resource type and name string, also

        the end of the resource table.

   DB   ASCII text of the type or name string.

======================================================================

                         RESIDENT-NAME TABLE

======================================================================

The resident-name table follows the resource table, and contains this

module's name string and resident exported procedure name strings. The

first string in this table is this module's name. These name strings

are case-sensitive and are not null-terminated. The following

describes the format of the name strings:

   Size Description

   ---- -----------

   DB   Length of the name string that follows. A zero value indicates

        the end of the name table.

   DB   ASCII text of the name string.

   DW   Ordinal number (index into entry table). This value is ignored

        for the module name.

======================================================================

                        MODULE-REFERENCE TABLE

======================================================================

The module-reference table follows the resident-name table. Each entry

contains an offset for the module-name string within the imported-

names table; each entry is 2 bytes long.

   Size Description

   ---- -----------

   DW   Offset within Imported Names Table to referenced module name

        string.

======================================================================

                         IMPORTED-NAME TABLE

======================================================================

The imported-name table follows the module-reference table. This table

contains the names of modules and procedures that are imported by the

executable file. Each entry is composed of a 1-byte field that

contains the length of the string, followed by any number of

characters. The strings are not null-terminated and are case

sensitive.

   Size Description

   ---- -----------

   DB   Length of the name string that follows.

   DB   ASCII text of the name string.

======================================================================

                             ENTRY TABLE

======================================================================

The entry table follows the imported-name table. This table contains

bundles of entry-point definitions. Bundling is done to save space in

the entry table. The entry table is accessed by an ordinal value.

Ordinal number one is defined to index the first entry in the entry

table. To find an entry point, the bundles are scanned searching for a

specific entry point using an ordinal number. The ordinal number is

adjusted as each bundle is checked. When the bundle that contains the

entry point is found, the ordinal number is multiplied by the size of

the bundle's entries to index the proper entry.

The linker forms bundles in the most dense manner it can, under the

restriction that it cannot reorder entry points to improve bundling.

The reason for this restriction is that other .EXE files may refer to

entry points within this bundle by their ordinal number. The following

describes the format of the entry table bundles.

   Size Description

   ---- -----------

   DB   Number of entries in this bundle. All records in one bundle

        are either moveable or refer to the same fixed segment. A zero

        value in this field indicates the end of the entry table.

   DB   Segment indicator for this bundle. This defines the type of

        entry table entry data within the bundle. There are three

        types of entries that are defined.

        000h = Unused entries. There is no entry data in an unused

               bundle. The next bundle follows this field. This is

               used by the linker to skip ordinal numbers.

        001h-0FEh = Segment number for fixed segment entries. A fixed

               segment entry is 3 bytes long and has the following

               format.

            DB  Flag word.

                01h = Set if the entry is exported.

                02h = Set if the entry uses a global (shared) data

                      segments.

                      The first assembly-language instruction in the

                      entry point prologue must be "MOV AX,data

                      segment number". This may be set only for

                      SINGLEDATA library modules.

            DW  Offset within segment to entry point.

        0FFH = Moveable segment entries. The entry data contains the

               segment number for the entry points. A moveable segment

               entry is 6 bytes long and has the following format.

            DB  Flag word.

                01h = Set if the entry is exported.

                02h = Set if the entry uses a global (shared) data

                      segments.

            INT 3FH.

            DB  Segment number.

            DW  Offset within segment to entry point.

======================================================================

                        NONRESIDENT-NAME TABLE

======================================================================

The nonresident-name table follows the entry table, and contains a

module description and nonresident exported procedure name strings.

The first string in this table is a module description. These name

strings are case-sensitive and are not null-terminated. The name

strings follow the same format as those defined in the resident name

table.

======================================================================

                           PER SEGMENT DATA

======================================================================

The location and size of the per-segment data is defined in the

segment table entry for the segment. If the segment has relocation

fixups, as defined in the segment table entry flags, they directly

follow the segment data in the file. The relocation fixup information

is defined as follows:

   Size Description

   ---- -----------

   DW   Number of relocation records that follow.

   A table of relocation records follows. The following is the format

   of each relocation record.

        DB  Source type.

            0Fh = SOURCE_MASK

            00h = LOBYTE

            02h = SEGMENT

            03h = FAR_ADDR (32-bit pointer)

            05h = OFFSET (16-bit offset)

        DB  Flags byte.

            03h = TARGET_MASK

            00h = INTERNALREF

            01h = IMPORTORDINAL

            02h = IMPORTNAME

            03h = OSFIXUP

            04h = ADDITIVE

        DW  Offset within this segment of the source chain.

            If the ADDITIVE flag is set, then target value is added to

            the source contents, instead of replacing the source and

            following the chain. The source chain is an 0FFFFh

            terminated linked list within this segment of all

            references to the target.

        The target value has four types that are defined in the flag

        byte field. The following are the formats for each target

        type:

        INTERNALREF

            DB  Segment number for a fixed segment, or 0FFh for a

                movable segment.

            DB  0

            DW  Offset into segment if fixed segment, or ordinal

                number index into Entry Table if movable segment.

        IMPORTNAME

            DW  Index into module reference table for the imported

                module.

            DW  Offset within Imported Names Table to procedure name

                string.

        IMPORTORDINAL

            DW  Index into module reference table for the imported

                module.

            DW  Procedure ordinal number.

        OSFIXUP

            DW  Operating system fixup type.

                Floating-point fixups.

                0001h = FIARQQ, FJARQQ

                0002h = FISRQQ, FJSRQQ

                0003h = FICRQQ, FJCRQQ

                0004h = FIERQQ

                0005h = FIDRQQ

                0006h = FIWRQQ

            DW  0

======================================================================

Microsoft is a registered trademark and Windows is a trademark of

Microsoft Corporation.

Additional reference words: 3.00 3.10 softlib EXEFMT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrFmt


Font-File Format

Article ID: Q65123

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

NOTE: This article is part of a set of seven articles, collectively

called the "Windows 3.00 Developer's Notes." More information about

the contents of the other articles, and procedures for ordering a

hard-copy set, can be found in the Microsoft Knowledge Base article:

   ARTICLE-ID: Q65260

   TITLE     : The Windows 3.00 Developer's Notes

Download FONTFMT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FONTFMT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FONTFMT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FONTFMT.EXE

MORE INFORMATION

================

Formats for Microsoft Windows font files are defined for both raster

and vector fonts. These formats can be used by smart text generators

in some GDI support modules. The vector formats, in particular, are

more frequently used by GDI itself than by support modules.

Both raster and vector font files begin with information that is

common to both, and then continue with information that differs for

each type of file.

For Windows 3.0, the font-file header includes six new fields:

dFlags, dfAspace, dfBspace, dfCspace, dfColorPointer, and dfReserved1.

These fields are not used in Windows 3.0. To ensure compatibility

with future versions of Windows, these fields should be set to zero.

All device drivers support the Windows 2.x fonts. However, not all

device drivers support the Windows 3.0 version.

Windows 3.0 font files include the glyph table in dfCharTable, which

consists of structures that describe the bits for characters in the

font file. This version enables fonts to exceed 64K in size, the size

limit of Windows 2.x fonts. This is made possible by the use of 32-bit

offsets to the character glyphs in dfCharTable.

Because of the 32-bit offsets and their potentially large size, these

fonts are designed for use on systems that are running Windows version

3.0 in protected (standard or 386 enhanced) mode with an 80386 (or

higher) processor where the processor's 32-bit registers can access

the character glyphs. Typically, device drivers use the Windows 3.0

version of a font only when both of these conditions are true.

Font files are stored with an .FNT extension of the form NAME.FNT. The

information at the beginning of both raster and vector versions of

Windows 3.0 font files is shown in the following list:

Field          Description

-----          -----------

dfVersion      2 bytes specifying the version (0200H or 0300H) of

               the file.

dfSize         4 bytes specifying the total size of the file in

               bytes.

dfCopyright    60 bytes specifying copyright information.

dfType         2 bytes specifying the type of font file.

               The low-order byte is exclusively for GDI use. If the

               low-order bit of the WORD is zero, it is a bitmap

               (raster) font file. If the low-order bit is 1, it is a

               vector font file. The second bit is reserved and must

               be zero. If no bits follow in the file and the bits are

               located in memory at a fixed address specified in

               dfBitsOffset, the third bit is set to 1; otherwise, the

               bit is set to 0 (zero). The high-order bit of the low

               byte is set if the font was realized by a device. The

               remaining bits in the low byte are reserved and set to

               zero.

               The high byte is reserved for device use and will

               always be set to zero for GDI-realized standard fonts.

               Physical fonts with the high-order bit of the low byte

               set may use this byte to describe themselves. GDI will

               never inspect the high byte.

dfPoints       2 bytes specifying the nominal point size at which

               this character set looks best.

dfVertRes      2 bytes specifying the nominal vertical resolution

               (dots-per-inch) at which this character set was

               digitized.

dfHorizRes     2 bytes specifying the nominal horizontal resolution

               (dots-per-inch) at which this character set was

               digitized.

dfAscent       2 bytes specifying the distance from the top of a

               character definition cell to the baseline of the

               typographical font. It is useful for aligning the

               baselines of fonts of different heights.

dfInternalLeading

               Specifies the amount of leading inside the bounds set

               by dfPixHeight. Accent marks may occur in this area.

               This may be zero at the designer's option.

dfExternalLeading

               Specifies the amount of extra leading that the designer

               requests the application add between rows. Since this

               area is outside of the font proper, it contains no

               marks and will not be altered by text output calls in

               either the OPAQUE or TRANSPARENT mode. This may be zero

               at the designer's option.

dfItalic       1 (one) byte specifying whether or not the character

               definition data represent an italic font. The low-order

               bit is 1 if the flag is set. All the other bits are

               zero.

dfUnderline    1 byte specifying whether or not the character

               definition data represent an underlined font. The

               low-order bit is 1 if the flag is set. All the other

               bits are 0 (zero).

dfStrikeOut    1 byte specifying whether or not the character

               definition data represent a struckout font. The low-

               order bit is 1 if the flag is set. All the other bits

               are zero.

dfWeight       2 bytes specifying the weight of the characters in the

               character definition data, on a scale of 1 to 1000. A

               dfWeight of 400 specifies a regular weight.

dfCharSet      1 byte specifying the character set defined by this

               font.

dfPixWidth     2 bytes. For vector fonts, specifies the width of the

               grid on which the font was digitized. For raster fonts,

               if dfPixWidth is nonzero, it represents the width for

               all the characters in the bitmap; if it is zero, the

               font has variable width characters whose widths are

               specified in the dfCharTable array.

dfPixHeight    2 bytes specifying the height of the character bitmap

               (raster fonts), or the height of the grid on which a

               vector font was digitized.

dfPitchAndFamily

               Specifies the pitch and font family. The low bit is set

               if the font is variable pitch. The high four bits give

               the family name of the font. Font families describe in

               a general way the look of a font. They are intended for

               specifying fonts when the exact face name desired is

               not available. The families are as follows:

                  Family               Description

                  ------               -----------

                  FF_DONTCARE (0<<4)   Don't care or don't know.

                  FF_ROMAN (1<<4)      Proportionally spaced fonts

                                       with serifs.

                  FF_SWISS (2<<4)      Proportionally spaced fonts

                                       without serifs.

                  FF_MODERN (3<<4)     Fixed-pitch fonts.

                  FF_SCRIPT (4<<4)

                  FF_DECORATIVE (5<<4)

dfAvgWidth     2 bytes specifying the width of characters in the font.

               For fixed-pitch fonts, this is the same as dfPixWidth.

               For variable-pitch fonts, this is the width of the

               character "X."

dfMaxWidth     2 bytes specifying the maximum pixel width of any

               character in the font. For fixed-pitch fonts, this is

               simply dfPixWidth.

dfFirstChar    1 byte specifying the first character code defined by

               this font. Character definitions are stored only for

               the characters actually present in a font. Therefore,

               use this field when calculating indexes into either

               dfBits or dfCharOffset.

dfLastChar     1 byte specifying the last character code defined by

               this font. Note that all the characters with codes

               between dfFirstChar and dfLastChar must be present in

               the font character definitions.

dfDefaultChar  1 byte specifying the character to substitute

               whenever a string contains a character out of the

               range. The character is given relative to dfFirstChar

               so that dfDefaultChar is the actual value of the

               character, less dfFirstChar. The dfDefaultChar should

               indicate a special character that is not a space.

dfBreakChar    1 byte specifying the character that will define word

               breaks. This character defines word breaks for word

               wrapping and word spacing justification. The character

               is given relative to dfFirstChar so that dfBreakChar is

               the actual value of the character, less that of

               dfFirstChar. The dfBreakChar is normally (32 -

               dfFirstChar), which is an ASCII space.

dfWidthBytes   2 bytes specifying the number of bytes in each row of

               the bitmap. This is always even, so that the rows start

               on WORD boundaries. For vector fonts, this field has no

               meaning.

dfDevice       4 bytes specifying the offset in the file to the string

               giving the device name. For a generic font, this value

               is zero.

dfFace         4 bytes specifying the offset in the file to the

               null-terminated string that names the face.

dfBitsPointer  4 bytes specifying the absolute machine address of

               the bitmap. This is set by GDI at load time. The

               dfBitsPointer is guaranteed to be even.

dfBitsOffset   4 bytes specifying the offset in the file to the

               beginning of the bitmap information. If the 04H bit in

               the dfType is set, then dfBitsOffset is an absolute

               address of the bitmap (probably in ROM).

               For raster fonts, dfBitsOffset points to a sequence of

               bytes that make up the bitmap of the font, whose height

               is the height of the font, and whose width is the sum

               of the widths of the characters in the font rounded up

               to the next WORD boundary.

               For vector fonts, it points to a string of bytes or

               words (depending on the size of the grid on which the

               font was digitized) that specify the strokes for each

               character of the font. The dfBitsOffset field must be

               even.

dfReserved     1 byte, not used.

dfFlags        4 bytes specifying the bits flags, which are additional

               flags that define the format of the Glyph bitmap, as

               follows:

               DFF_FIXED            equ  0001h ; font is fixed pitch

               DFF_PROPORTIONAL     equ  0002h ; font is proportional

                                               ; pitch

               DFF_ABCFIXED         equ  0004h ; font is an ABC fixed

                                               ; font

               DFF_ABCPROPORTIONAL  equ  0008h ; font is an ABC pro-

                                               ; portional font

               DFF_1COLOR           equ  0010h ; font is one color

               DFF_16COLOR          equ  0020h ; font is 16 color

               DFF_256COLOR         equ  0040h ; font is 256 color

               DFF_RGBCOLOR         equ  0080h ; font is RGB color

dfAspace       2 bytes specifying the global A space, if any. The

               dfAspace is the distance from the current position to

               the left edge of the bitmap.

dfBspace       2 bytes specifying the global B space, if any. The

               dfBspace is the width of the character.

dfCspace       2 bytes specifying the global C space, if any. The

               dfCspace is the distance from the right edge of the

               bitmap to the new current position. The increment of a

               character is the sum of the three spaces. These apply

               to all glyphs and is the case for DFF_ABCFIXED.

dfColorPointer

               4 bytes specifying the offset to the color table for

               color fonts, if any. The format of the bits is similar

               to a DIB, but without the header. That is, the

               characters are not split up into disjoint bytes.

               Instead, they are left intact. If no color table is

               needed, this entry is NULL.

               [NOTE: This information is different from that in the

               hard-copy Developer's Notes and reflects a correction.]

dfReserved1    16 bytes, not used.

               [NOTE: This information is different from that in the

               hard-copy Developer's Notes and reflects a correction.]

dfCharTable    For raster fonts, the CharTable is an array of entries

               each consisting of two 2-byte WORDs for Windows 2.x and

               three 2-byte WORDs for Windows 3.0. The first WORD of

               each entry is the character width. The second WORD of

               each entry is the byte offset from the beginning of the

               FONTINFO structure to the character bitmap. For Windows

               3.0, the second and third WORDs are used for the

               offset.

               There is one extra entry at the end of this table that

               describes an absolute-space character. This entry

               corresponds to a character that is guaranteed to be

               blank; this character is not part of the normal

               character set.

               The number of entries in the table is calculated as

               ((dfLastChar - dfFirstChar) + 2). This includes a

               spare, the sentinel offset mentioned in the following

               paragraph.

               For fixed-pitch vector fonts, each 2-byte entry in this

               array specifies the offset from the start of the bitmap

               to the beginning of the string of stroke specification

               units for the character. The number of bytes or WORDs

               to be used for a particular character is calculated by

               subtracting its entry from the next one, so that there

               is a sentinel at the end of the array of values.

               For proportionally spaced vector fonts, each 4-byte

               entry is divided into two 2-byte fields. The first

               field gives the starting offset from the start of the

               bitmap of the character strokes. The second field gives

               the pixel width of the character.

<facename>     An ASCII character string specifying the name of the

               font face. The size of this field is the length of the

               string plus a NULL terminator.

<devicename>   An ASCII character string specifying the name of the

               device if this font file is for a specific device. The

               size of this field is the length of the string plus a

               NULL terminator.

<bitmaps>      This field contains the character bitmap definitions.

               Each character is stored as a contiguous set of bytes.

               (In the old font format, this was not the case.)

               The first byte contains the first 8 bits of the first

               scanline (that is, the top line of the character). The

               second byte contains the first 8 bits of the second

               scanline. This continues until a first "column" is

               completely defined.

               The following byte contains the next 8 bits of the

               first scanline, padded with zeros on the right if

               necessary (and so on, down through the second

               "column"). If the glyph is quite narrow, each scanline

               is covered by 1 byte, with bits set to zero as

               necessary for padding. If the glyph is very wide, a

               third or even fourth set of bytes can be present.

                  NOTE: The character bitmaps must be stored

                  contiguously and arranged in ascending order.

               The following is a single-character example, in which

               are given the bytes for a 12 x 14 pixel character, as

               shown here schematically.

                  ............

                  .....**.....

                  ....*..*....

                  ...*....*...

                  ..*......*..

                  ..*......*..

                  ..*......*..

                  ..********..

                  ..*......*..

                  ..*......*..

                  ..*......*..

                  ............

                  ............

                  ............

               The bytes are given here in two sets, because the

               character is less than 17 pixels wide.

                  00 06 09 10 20 20 20 3F 20 20 20 00 00 00

                  00 00 00 80 40 40 40 C0 40 40 40 00 00 00

               Note that in the second set of bytes, the second digit

               of each is always zero. It would correspond to the 13th

               through 16th pixels on the right side of the character,

               if they were present.

The Windows 2.x version of dfCharTable has a GlyphEntry structure with

the following format:

GlyphEntry    struc

geWidth       dw     ?    ; width of character bitmap in pixels

geOffset      dw     ?    ; pointer to the bits

GlyphEntry    ends

The Windows 3.0 version of the dfCharTable is dependent on the format

of the Glyph bitmap.

   NOTE: The only formats supported in Windows 3.0 will be DFF_FIXED

   and DFF_PROPORTIONAL.

DFF_FIXED

DFF_PROPORTIONAL

GlyphEntry    struc

geWidth       dw     ?    ; width of character bitmap in pixels

geOffset      dd     ?    ; pointer to the bits

GlyphEntry    ends

DFF_ABCFIXED

DFF_ABCPROPORTIONAL

GlyphEntry    struc

geWidth       dw     ?   ; width of character bitmap in pixels

geOffset      dd     ?   ; pointer to the bits

geAspace      dd     ?   ; A space in fractional pixels (16.16)

geBspace      dd     ?   ; B space in fractional pixels (16.16)

geCspace      dw     ?   ; C space in fractional pixels (16.16)

GlyphEntry    ends

The fractional pixels are expressed as a 32-bit signed number with an

implicit binary point between bits 15 and 16. This is referred to as a

16.16 ("sixteen dot sixteen") fixed-point number.

The ABC spacing here is the same as that defined above. However, here

there are specific sets for each character.

DFF_1COLOR

DFF_16COLOR

DFF_256COLOR

DFF_RGBCOLOR

GlyphEntry    struc

geWidth       dw     ?   ; width of character bitmap in pixels

geOffset      dd     ?   ; pointer to the bits

geHeight      dw     ?   ; height of character bitmap in pixels

geAspace      dd     ?   ; A space in fractional pixels (16.16)

geBspace      dd     ?   ; B space in fractional pixels (16.16)

geCspace      dd     ?   ; C space in fractional pixels (16.16)

GlyphEntry    ends

DFF_1COLOR means 8 pixels per byte

DFF_16COLOR means 2 pixels per byte

DFF_256COLOR means 1 pixel per byte

DFF_RGBCOLOR means RGBquads

Microsoft is a registered trademark and Windows is a trademark of

Microsoft Corporation.

Additional reference words: 3.00 3.10 softlib FONTFMT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrFmt


Aligning Columns in a Windows 3.x List Box

Article ID: Q66240

------------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

------------------------------------------------------------------------

SUMMARY

=======

To align columns of text in a list box in an application running under

Windows version 3.0, the suggested approach is to use the proportional

system font and to use tab characters to align the text. For tabs to work

properly, you must specify the LBS_USETABSTOPS style when you create the

list box.

Code that depends on space characters for correct alignment of text does

not work correctly with the Windows proportional system font. This is a

common problem when migrating applications written for Windows 2.x and

earlier to Windows 3.0. This problem can be corrected by using tabs, or by

using a fixed-pitch font in the list box.

MORE INFORMATION

================

One particular fixed-pitch font is always available as a system resource.

This font, identified as the SYSTEM_FIXED_FONT, is used by applications

developed for previous versions of Windows that have not been marked for

Windows 3.0 font compatibility.

To use a fixed font in a dialog box, you must send each control a

WM_SETFONT message as part of the dialog box's initialization process. The

handle to the font is passed in wParam for the message. When lParam

contains a nonzero value, the control redraws itself using the new font. An

lParam of zero omits the redraw. Below is a small code fragment that

demonstrates the processing of the WM_INITDIALOG message. ID_CONTROL

represents the control ID of the list box (or other control).

  HFONT   hFixedFont;

  ...

  case WM_INITDIALOG:

          hFixedFont = GetStockObject(SYSTEM_FIXED_FONT);

          SendDlgItemMessage(hDlg, ID_CONTROL, WM_SETFONT,

                             hFixedFont, 0L);

          ... /* possibly other processing */

          break;

The following code fragment selects a fixed font into a device context

(DC):

  HFONT   hFixedFont;

  ...

  hFixedFont = GetStockObject(SYSTEM_FIXED_FONT);

  hOldFont   = SelectObject (hDC, hFixedFont);

  ...

  /* before calling DeleteDC() or ReleaseDC(),

   * restore original font */

  SelectObject(hDC, hOldFont);

  ...

More information on this and other subjects related to Windows

programming is contained in the file TIPS.TXT. The SDK installation

program places this file in the WINDEV directory, with the other SDK

files. TIPS.TXT contains a set of notes provided by Microsoft Product

Support Services to help answer some of the most commonly asked

questions by developers of Windows 3.0 applications. The notes are

addressed to new Windows developers as well as to those moving Windows

2.x applications to Windows 3.0.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


Possible Causes for System Resource Reduction

Article ID: Q66654

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

You can note via Program Manager's "About Box" that Windows's System

Resources can be inadvertently reduced by a Windows-based application,

causing subsequent RegisterWindow() or CreateWindow() function calls

to fail.

The system resources are a reflection of the lower USER and GDI's data

segments. The following steps eliminate the major causes of USER's

data segment fill-up listed in each step:

1. Ensure that the cbClsExtraBytes and cbWndExtraBytes are set to 0 in

   the WNDCLASS structure, unless the application is definitely using

   them.

2. Ensure that a MakeProcInstance() is performed and the window

   procedure is EXPORTed in the .DEF file.

3. Use CVW to verify that the application is receiving the WM_CREATE

   message.

4. Confirm that all menus created, loaded, or added dynamically [that is,

   using CreateMenu(), AppendMenu(), and so forth] are properly destroyed

   before terminating the application.

The main reason why GDI's data segment fills up is that objects are being

created and are not being destroyed when they are no longer needed.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrSys


Dialog Box Creation Fails If Text Starts w/ Character 255

Article ID: Q66926

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Text strings in a dialog box resource cannot start with the character

represented by the value 255 (0xFF). In the ANSI character set, this

character is the letter "y" with a diaeresis mark, which is used primarily

in Nordic languages. If Windows encounters this situation, a call to

DialogBox() or CreateDialog() will fail.

The following are two possible solutions:

 - Create the control with some "dummy" text. Then, use the

   SetDlgItemText() function during the processing of the WM_INITDIALOG

   message to manually set the text of the control to its proper value.

   This is the preferred method.

   -or-

 - Instead of starting the text with the 255 character, use a space,

   followed by a backspace character and the 255 character. For example,

   the text in the dialog box script can be " \0008x", where "x" is the

   255 character. The embedded backspace erases the space, leaving only

   the 255 character.

MORE INFORMATION

================

Windows uses the number 255 to indicate that a resource is represented by

ordinal value instead of by a string name. For example, when a dialog box

is declared as follows

   AboutBox    DIALOG  ...

the text "AboutBox" appears in the .RES file. However, using the following

   1           DIALOG  ...

places the bytes 0xFF 0x01 0x00 into the .RES file. The 0xFF is used to

indicate that the next two bytes are the ordinal value for this resource.

When creating a dialog box, the Windows Dialog Manager scans through each

string in the dialog box template to find the null terminator. However,

when a string that starts with 255 is encountered, it is interpreted as an

ordinal value. In this situation, Windows incorrectly skips the next 2

bytes and treats the new position as the next piece of data in the dialog

box template.

Whenever this occurs, the remainder of the dialog box template is

interpreted incorrectly, and Windows tries to create controls of unknown

classes, with unknown styles, in unknown locations. This causes the dialog

box creation to fail.

For additional information about dialog box creation failure reasons, query

on the following words in the Microsoft Knowledge Base:

   createdialog and createdialogindirect and dialogbox and creation

Additional reference words: 3.00 3.10 dialog box ANSI

KBCategory: kbprg

KBSubcategory: UsrDlgs


Inserting Right Justified Text in a Menu in Windows

Article ID: Q67063

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The "\a" character used with the InsertMenu() function is NOT considered to

be a C language "\a", but is instead considered to be a resource compiler

"\a". This code in the resource compiler is translated to a backspace

character. Thus, an "\a" used in the resource compiler is really considered

to be a "\b" or an "\x08" within the C Language.

When an "\x08" (backspace) is used, the menu item behaves as expected.

However, you must place at least one character, which can be a space,

before the "\b". For example:

   (LPSTR)" \bsometext"

NOTE: This is still true in Windows 3.1; however, the leading blank is not

necessary. The above example should be modified as follows:

   (LPSTR)"\bsometext"

This is not the case for Windows 95. In Windows 95, the MFT_RIGHTJUSTIFY

flag should be used with InsertMenuItem()/SetMenuItemInfo/MENUEX resource.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMen


Using Window Extra Bytes in Custom Controls

Article ID: Q67249

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows environment, custom controls are often

designed to store data about their state, color, or position. This

data can be stored directly in window extra bytes associated with the

custom control window or in a local or a global memory object.

If a control uses window extra bytes directly, Windows allocates

memory from the user heap, which is a scarce system resource shared by

all applications. In contrast, the LocalAlloc function allocates

memory from the heap of the application or the dynamic-link library

(DLL) in which the control is implemented.

If six or fewer bytes of data are required for each instance of a

custom control, the demand placed on the system user heap is not

large. In contrast, each window in Windows version 3.0 requires at

least 62 bytes of user heap; therefore, using a small number of window

extra bytes is easily justified.

If the control requires more than six bytes of data, the control class

should set the number of window extra bytes to the size of one HANDLE

data type. When the control is created, call the LocalAlloc function

to allocate enough memory to hold the data associated with the

control. Store the handle that LocalAlloc returns in the window extra

bytes.

MORE INFORMATION

================

Depending on the amount of storage required, storing a handle to a

local memory block in the window extra bytes is usually advantageous.

This method requires calling the LocalAlloc function once at

initialization time and calling the LocalLock and LocalUnlock

functions each time the control processes a message that refers to or

modifies any status information. Calling LocalLock and LocalUnlock is

much faster than calling GetWindowWord to access each item of data.

Storing a memory handle in the window extra bytes also provides the

control the option of using a global memory block if a very large

amount of data must be stored.

Using an allocated memory also allows the application to vary the

amount of data stored for each custom control by storing the size of

the structure or an index that describes the structure at the

beginning of the block of memory.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


How to Respond When DDE Data Cannot Be Locked

Article ID: Q67653

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

A Dynamic Data Exchange (DDE) client application receives a WM_DDE_DATA

message when the DDE server has data to transmit. The low-order word of

lParam contains the handle to a global memory object containing the data.

If the DDE client is unable to lock the handle to access the data

[GlobalLock() returns NULL], the DDE client should send a negative

acknowledgment to the DDE server. A negative acknowledgment is a WM_DDE_ACK

message with the fAck bit set to zero.

DDE is discussed in Chapter 15 of the "Microsoft Windows Software

Development Kit Reference Volume 2."

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


List Box and Combo Box Capacity Limits

Article ID: Q67678

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, the storage capacity of a

list box or combo box is limited by the total amount of text. Each item is

stored in memory as a NULL-terminated string.

The maximum amount of memory that a list box or combo box can use to store

text depends on the version of Windows in use. In Windows versions 2.x, the

amount of free memory in the user module's data segment limits available

storage.

Beginning with Windows 3.0, each list box or combo box has its own data

segment, which allows it to store 64K of text. If a list box or combo box

in an application must store more text, the application can store up to

8160 items in an owner-draw list box or combo box that does not have the

LBS_HASSTRINGS list box or CBS_HASSTRINGS combo box style. In this case,

the application stores and manages the item text separately.

MORE INFORMATION

================

An owner-draw list box or owner-draw combo box is limited to 64K of data

storage, as are regular (nonowner draw) list boxes and combo boxes. Because

the application manages the text when the list box or combo box do not have

the LBS_HASSTRINGS or CBS_HASSTRINGS styles, each item in an owner-draw

list box or owner-draw combo box require 8 bytes, 4 of which store the

application-supplied 32-bit item-identifier value.

The list box (or combo box) uses 256 bytes of the 64K segment for internal

storage, and uses the rest for items. This yields room for 8160 items, as

follows:

   (64K segment - 256 bytes) / (8 bytes per item)

NOTE: In a list box with the LBS_HASSTRINGS style or combo box with the

CBS_HASSTRINGS style, the text pointed to by the pointer passed in the

lParam of LB_ADDSTRING or CB_ADDSTRING (or LB_INSERTSTRING or

CB_INSERTSTRING) is stored in the list box's or combo box's storage area.

An additional 32-bit storage value can be associated with each item with

the LB_SETITEMDATA or CB_SETITEMDATA styles.

When the LBS_HASSTRINGS or CBS_HASSTRINGS styles are not present, Windows

no longer stores text for the list box or combo box. Instead of storing the

text pointed to by the lParam of LB_ADDSTRING or CB_ADDSTRING (or

LB_INSERTSTRING or CB_INSERTSTRING), only the 32-bit value itself is

stored, thus dramatically reducing the needed storage. When the owner-draw

list box or owner-draw combo box receive the WM_DRAWITEM message, it is up

to the drawing routine to interpret the 32-bit value.

Additional reference words: 3.00 3.10 listbox combobox list-box combo-box

KBCategory: kbprg

KBSubcategory: UsrCtl


Control Panel Doesn't Respond to WM_WININICHANGE Messages

Article ID: Q68360

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Control Panel application does not respond to WM_WININICHANGE messages

under Windows. Microsoft considered including this functionality; however,

it was decided that, because the Control Panel changes various items in the

system configuration file (WIN.INI), responding to a WM_WININICHANGE

message could cause a conflict. (For example, if another application

changes the text color while the Control Panel has its color dialog

displayed, what is the proper action for the Control Panel?)

To work around this potential problem, the Control Panel reinitializes

itself each time a new dialog box is displayed. However, this

initialization does not involve querying the WIN.INI file with

GetProfileString().

MORE INFORMATION

================

Windows caches the WIN.INI file. Therefore, if a regular text editor

(other than Notepad) is used to modify the file, the disk file is

updated, however, the cache is not.

When a WM_WININICHANGE message is broadcast to all top-level windows,

each application can check the WIN.INI cache for relevant changes.

However, applications will not look at the WIN.INI file on disk.

One way to update the cache is to exit Windows and restart. Another

way to update the cache is to call WriteProfileString(NULL,NULL,NULL),

which forces a flush of the cache. A subsequent call to

GetProfileString() will cause the WIN.INI file on disk to be read into

the cache.

However, the changes will not be reflected by the Control Panel unless

the user exits and re-enters Windows. Reflecting changes to WIN.INI in

the Control Panel without first exiting Windows is under consideration

for inclusion in a future release of Windows.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrIni


Avoid SetClassLong If Subclassing a Standard Control Class

Article ID: Q68584

-------------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

-------------------------------------------------------------------------

An application should not attempt to create a window subclass for standard

Windows controls such as combo boxes and buttons.

SetClassLong() should not be used to subclass an entire standard control

class. This would cause all controls of that type (including controls in

other applications) created while the subclass was in effect to be

subclassed.

SetWindowLong() can be used to subclass individual controls in your

application.

In addition, standard Windows controls should only be subclassed in "non-

intrusive" ways. Subclassing procedures that alter the appearance of a

control or that depend on undocumented messages or message parameters could

be incompatible with future versions of Windows.

For more information on subclassing a control, please see the following

article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q101180

   TITLE     : Safe Subclassing

Charles Petzold's "Programming Windows" (Microsoft Press) contains a

sample program that shows how to subclass a standard control (in this

case, a scroll bar). In the Windows 2.x version of the book, the

sample is called COLORSCR; in the Windows 3.0 version, the sample is

called COLORS1.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


How to Give a 3-D Effect to Windows Controls

Article ID: Q69079

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows (SDK)

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

It is possible for an application to give edit controls, list boxes, and

static text a three-dimensional (3-D) appearance. Each control can be made

to appear recessed into the surface of its parent dialog box, or raised

above it. This article contains the code necessary to implement this

effect.

MORE INFORMATION

================

There are three steps required to give a particular control a 3-D

appearance:

1. Remove the WS_BORDER attribute from the control specification in

   the dialog template. This will cause the background of the control

   to "blend" into the background of the dialog.

2. In the WM_PAINT message of the control's parent dialog function,

   post a user-defined message to the dialog function. Return FALSE

   for the processing of WM_PAINT so that all other painting will take

   place. By posting the user-defined message, the Dialog Manager will

   do its painting first, then the three-dimensional appearance will

   be added.

3. During the processing of the user defined message, call

   DrawIndent() for each control. DrawIndent() will draw a highlight

   color on the right side and bottom of the control, and a shadow

   color on the top and left sides of the control. This will give the

   appearance that the control is recessed into the dialog box. To

   make the control appear raised above the dialog, reverse the

   highlight and shadow colors in the DrawIndent() function call.

On systems with a monochrome display, DrawIndent() will only draw a

single black border.

The following code shows how to use DrawIndent():

    ...

    case WM_PAINT:

       PostMessage(hDlg, WM_COMMAND, IDM_REPAINT, 0L);

       return FALSE;

    case WM_COMMAND:

       switch (wParam)

         {

         case IDM_REPAINT:

           DrawIndent(hDlg, IDD_FIELD1);

           DrawIndent(hDlg, IDD_FIELD2);

             ...

           DrawIndent(hDlg, IDD_FIELDN);

           break;

    ...

The following is the code for DrawIndent():

void DrawIndent(HWND hDlg, int ID)

// Assumptions:

//

// hDlg        is a valid window handle.

// ID          is a valid control ID.

// bMonochrome is a flag that is TRUE for a monochrome system.

//

{

  RECT rRect;

  HDC  hDC;

  HPEN hOldPen;

  GetClientRect(GetDlgItem(hDlg, ID), (LPRECT)&rRect);

  // By modifying the parameters this way, things are centered a bit

  // better.

  rRect.left   -= 2;

  rRect.bottom -= 1;

  rRect.top    -= 3;

  hDC = GetDC(GetDlgItem(hDlg, ID));

  // Draw the Shadow

  hOldPen = SelectObject(hDC, GetStockObject(BLACK_PEN));

  MoveTo(hDC, rRect.left-1, rRect.bottom+1);

  LineTo(hDC, rRect.left-1, rRect.top-1);

  LineTo(hDC, rRect.right+1, rRect.top-1);

  if (!bMonochrome)

    {

    MoveTo(hDC, rRect.left-2, rRect.bottom+2);

    LineTo(hDC, rRect.left-2, rRect.top-2);

    LineTo(hDC, rRect.right+2, rRect.top-2);

    // On color systems, select the highlight color

    SelectObject(hDC, GetStockObject(WHITE_PEN));

    }

  // Draw the Highlight (still shadow for mono systems)

  MoveTo(hDC, rRect.right+1, rRect.top-1);

  LineTo(hDC, rRect.right+1, rRect.bottom+1);

  LineTo(hDC, rRect.left-1, rRect.bottom+1);

  if (!bMonochrome)

    {

    MoveTo(hDC, rRect.right+2, rRect.top-2);

    LineTo(hDC, rRect.right+2, rRect.bottom+2);

    LineTo(hDC, rRect.left-2, rRect.bottom+2);

    }

  // Housekeep

  SelectObject(hDC, hOldPen);

  ReleaseDC(GetDlgItem(hDlg, ID), hDC);

}

For additional information, please see the following article(s) in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q97361

   TITLE     : Adding 3-D Controls Using CTL3D.DLL

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


Fatal Exit Code 0x0506 Definition

Article ID: Q69888

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Fatal Exit code 0x0506 is not documented in Appendix C of the "Microsoft

Windows Software Development Kit Reference Volume 2" version 3.0.

This Fatal Exit will occur if the GetProfileString() or

GetPrivateProfileString() function is called with the lpDefault parameter

set to NULL. lpDefault specifies a string to return in the lpReturnedString

buffer if no match for lpKeyName is found.

To correct this Fatal Exit, always provide a valid string pointer for the

lpDefault parameter.

GetProfileString() and GetPrivateProfileString() are documented in the

Windows SDK "Reference, Volume 1" for version 3.0 and in the "Programmer's

Reference, Volume 2: Functions" for version 3.1.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrIni


Sources of Information Regarding Windows DDE

Article ID: Q69889

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The information below contains a list of references on Windows dynamic

data exchange (DDE) and some tools that can be used to test DDE

applications developed with the Windows SDK versions 3.0 and 3.1.

MORE INFORMATION

================

PRINTED DOCUMENTATION

=====================

DDE Specification

-----------------

 - "Microsoft Windows Software Development Kit Reference Volume 2,"

   Chapter 15, "Windows DDE Protocol Definition."

 - "Microsoft Windows Software Development Kit Guide to Programming,"

   Chapter 22.

Books

-----

 - "Programming Windows," Second Edition (Charles Petzold, Microsoft

    Press), Chapter 17.

 - "Developing Windows 3.1 Applications with Microsoft C/C++," Second

   Edition (Brent E. Rector, Sams Publishing).

Microsoft Systems Journal Articles

----------------------------------

 - Vol. 5 No. 1 (January 1990), "Simplifying Complex Windows

   Development Through the Use of a Client-Server Interface."

 - Vol. 4 No. 3 (May 1989), "A Technical Study of Dynamic Data

   Exchange Under OS/2 Presentation Manager."

 - Vol. 8 No. 1 (January 1993), "Network DDE in Windows for Workgroups 3.1

   Bridges Programs Between PC's."

Sample Code

-----------

 - Windows 3.00 SDK DDE client and server applications (in the

   \SAMPLES\DDE directory)

 - DDEPOP and SHOWPOP sample applications in "Programming Windows."

COMMERCIAL APPLICATIONS THAT USE DDE

====================================

Below is a list of commercial applications that support DDE and the

conversation topics that each supports.

Microsoft Excel

---------------

See the index of the "Microsoft Excel User's Guide" for complete

references.

   Application  DDE Topics    Items

   -----------  ----------    -----

   NULL         NULL

   Excel        Sheet name    Cell reference (must be in R1C1 format)

   Excel        System        SysItems

   Excel        System        Formats (eight different kinds)

   Excel        System        Topics  (sheets that are loaded)

   Excel        System        Status  (busy or not)

Q+E

---

See pages 74-79 of the Q+E manual shipped with Microsoft Excel 3.00

for more information.

   Application  DDE Topics    Items

   -----------  ----------    -----

   NULL         NULL

   QE           System        SysItems

   QE           System        Formats = Biff TEXT

   QE           System        Topics  = Query1

   QE           System        Status  = Ready

   QE           System        Logon

   QE           System        Logoff

   QE           System        Sources

   QE           System        Tables

Microsoft Word for Windows

---------------------------

Please see the "Microsoft Word for Windows Technical Reference" manual

(published by Microsoft Press) for more information.

   Application  DDE Topics    Items

   -----------  ----------    -----

   NULL         NULL

   WinWord      Document      bookmark

   WinWord      System        SysItems

   WinWord      System        Formats (text, rtf, metafilepict,

                                       bitmap, link)

   WinWord      System        Topics  (documents that are loaded)

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


Reactivating First (and Only) Instance of an Application

Article ID: Q70074

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Sometimes restricting an application to a single instance is

desirable. In that case, when the user starts a second instance of the

application, a message box that says that the application is already

running can be displayed. A more user-friendly approach is to bring

the first instance to the front and activate it.

To accomplish this, perform the following four steps:

1. Obtain the main window handle of the first instance.

2. If the first instance has an open dialog box, obtain the window

   handle of its last active pop-up window.

3. Bring the parent and pop-up window (if present) to the front.

4. Do not run the second instance.

MORE INFORMATION

================

To determine whether an instance of the application is already

running, the first method below uses the FindWindow function to look

for the an application with the same main window class name. The

second method uses the hPrevInstance parameter to the WinMain

function.

The FindWindow method does not depend on any memory architecture or on

the hPrevInstance parameter; therefore, it is the suggested method for

future portability. The hPrevInstance assumes a memory architecture

for the operating system that allows a task to access another

application's data segments. In future versions of Windows, this may

not be possible if applications do not share the same local descriptor

table (LDT).

Method 1: Use FindWindow Function

---------------------------------

HWND FirsthWnd, FirstChildhWnd;

if (FirsthWnd = FindWindow("MyMainWindowClassName", NULL))

   {

   // Found another running application with the same class name.

   // Therefore, one instance is already running.

   // NOTE: "MyMainWindowClassName" must match the class name of the

   // program's main window. In the GENERIC sample application,

   // provided with the Microsoft Windows Software Development Kit,

   // versions 3.0 and 3.1, the chass name is "GenericWClass", which

   // is used in the InitApplication and InitInstance functions.

   FirstChildhWnd = GetLastActivePopup(FirsthWnd);

   BringWindowToTop(FirsthWnd);         // bring main window to top

   if (FirsthWnd != FirstChildhWnd)

      BringWindowToTop(FirstChildhWnd); // a pop-up window is active

                                        // bring it to the top too

   return FALSE;                        // do not run second instance

   }

Method 2: Use hPrevInstance Parameter

-------------------------------------

// Declare a global variable to save the handle of the first instance

// of the main window.

HWND FirsthWnd;

// Make the following modifications to the WinMain function:

HWND FirstChildhWnd;    // handle of last active pop-up window of the

                        // first application instance

if (!hPrevInstance)     // other instances of application running?

   if (!InitApplication(hInstance))  // initialize shared things

         return FALSE;  // exits if unable to initialize

   else {}

else  // a previous instance exists;

      // retrieve the main window handle from the first instance

   {

   GetInstanceData(hPrevInstance, (NPSTR)&FirsthWnd, 2);

   FirstChildhWnd = GetLastActivePopup(FirsthWnd);

   BringWindowToTop(FirsthWnd);         // bring main window to top

   if (FirsthWnd != FirstChildhWnd)

      BringWindowToTop(FirstChildhWnd); // a pop-up window is active

                                        // bring it to the top too

   return FALSE;                        // do not run second instance

   }

// Add this line to the InitApplication function:

FirsthWnd = NULL;  // no previous window, so this is NULL

// Add these two lines to the InitInstance function after the

// "hWnd = CreateWindow(...);" call:

if (!FirsthWnd)       // If this is the first instance,

   FirsthWnd = hWnd;  // save the window handle.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


PRB: SDK Sample Programs Define Delete Accelerator Incorrectly

Article ID: Q71147

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

The Windows Software Development Kit (SDK) sample applications that

define keyboard accelerators for the Edit menu define the Edit/Clear

accelerator incorrectly.

RESOLUTION

==========

To correct this problem, modify the RC file for each sample

application to remove VK_SHIFT from the Edit/Clear accelerator.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrMen


Tracking Down Lost System Resources

Article ID: Q71455

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The term "system resources" refers to two scarce system-wide

resources: the USER heap and the GDI heap. These two segments are each

limited to 64K, and they are both shared by all the applications

running under Windows.

During development of a Windows-based application, it is important to make

sure that all the system resources allocated by the application at run

time are released when the application terminates.

If too many system resources are lost, and either the USER heap or the

GDI heap gets too full, performance will degrade for the entire

Windows system.

The information below discusses how system resources can be "lost" by

an application, and how to track down and correct such problems when

they occur. In particular, it discusses:

1. Free System Resources -- A rough gauge of system resource use.

2. The GDI Heap -- The types of objects that are allocated in the GDI

   heap, and general rules for making sure that these objects are

   properly released.

3. The USER Heap -- The types of objects that are allocated in the

   USER heap, and general rules for making sure that these objects are

   properly released.

4. Troubleshooting and Heap Walker -- Specific techniques and tools for

   tracking down lost system resources.

MORE INFORMATION

================

Free System Resources

---------------------

The Program Manager's About Program Manager dialog box displays a Free

System Resources value. This value indicates the amount of room left

in the heap (USER or GDI) with the smallest amount of free space.

There is no Windows API call that an application can use to obtain

this value.

The easiest way to tell if an application is losing system resources

is to examine Program Manager's Free System Resources value before and

after

running the application. It is acceptable if this value goes down a

little the first time the application is run, however if the value

decreases every time the application runs and exits, system resources

are being allocated and not released.

The GDI Heap

------------

There are six GDI objects that a Windows program can create: pens,

brushes, fonts, bitmaps, regions, and palettes. Space for each of

these objects is allocated in the GDI heap.

Normally, the life cycle of a GDI object requires that the following

steps be performed:

1. Create the GDI object.

2. Use the object.

3. Delete the object.

The DeleteObject call is used to delete most GDI objects.

The three general rules for deleting GDI objects are:

1. An application deletes all GDI objects that it creates.

2. Do not delete GDI objects while they are selected into a valid

   device context.

3. Do not delete stock objects.

Also, the following calls should always be matched:

   CreateDC           -> DeleteDC

   CreateCompatibleDC -> DeleteDC

   CreateIC           -> DeleteDC

   GetDC              -> ReleaseDC

   BeginPaint         -> EndPaint

Creating GDI objects that are never destroyed is probably the most

common cause of lost system resources. A careful examination of every

place in the application's code that uses GDI objects will often

reveal the problem.

The debugging version of Windows 3.1 will FatalExit when an application

terminates if a GDI object owned by the application has not been deleted.

The USER Heap

-------------

When an application creates window classes, windows, and menus, these

objects take up room in the USER heap. When an application terminates,

Windows usually reclaims the memory used by objects in the USER heap.

Menus are a notable exception to this rule. Windows destroys the

current menu of a window that is being destroyed. Windows does not

destroy menus if they are not the current menu for any window. This

can cause problems for applications that switch between multiple

menus: the "extra" menus are not automatically destroyed when the

application terminates.

Therefore, if an application uses multiple menus, perform the

following steps:

1. Keep the handle to each menu.

2. When the application is terminating, use the GetMenu function to

   discover which menu is currently being used. Do not call the

   DestroyMenu function on this menu, Windows will destroy it

   automatically.

3. Call the DestroyMenu function to destroy each of the other menus.

   This will reclaim the memory in the USER heap that these menus were

   using.

Because the USER heap is a shared system resource, it is important

that an application does not allocate too many USER objects at once.

If the USER heap becomes too full, subsequent calls to the

RegisterClass and CreateWindow functions will fail.

This means that an application cannot create an excessively large

number of windows. Also, when calling the RegisterClass functions,

make sure that the cbWndExtra and cbClassExtra fields of the WNDCLASS

structure are explicitly set to 0 (zero) if no extra bytes are needed.

Also, the following calls should always be matched:

   CreateIcon   -> DestroyIcon

   CreateCursor -> DestroyCursor

Troubleshooting and Heap Walker

-------------------------------

As mentioned above, Program Manager's Free Systems Resources value can

provide evidence that memory objects are not being reclaimed in the

USER or GDI heaps.

It is sometimes unclear whether or not a particular Windows API call

that creates an object must be balanced by a later call to explicitly

delete the object. The following is a simple test that can be

performed to find out:

1. Alter the Generic sample application to ensure that it contains a

   loop that makes the API call in question 50 times, creating 50 of

   the objects in question.

2. Run this version of Generic repeatedly. If the Program Manager's Free

   System Resources value goes down every time Generic runs and exits,

   a balancing API call must be made to reclaim the system resources

   before Generic terminates.

The most powerful tool for looking at problems with lost system

resources is the Heap Walker application. Heap Walker is included with

the Microsoft Windows Software Development Kit (SDK). Chapter 11 of

the "Microsoft Windows Software Development Kit Tools" guide explains

how to use Heap Walker. In particular, page 11-8 outlines the

procedure for checking for leftover GDI objects.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrRsc


Menus Supported in Dialog Boxes w/o DS_MODALFRAME Style

Article ID: Q71499

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

Dialog boxes in Windows version 3.0 and later suppport menus as long

as the DS_MODALFRAME style is absent and the WS_SYSMENU style is

present. This behavior will continue to be supported in future

versions of Windows.

Dialogs with a modal frame and menu do not work and are not designed

to do so.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Keeping a Window on Top of All Other Windows

Article ID: Q71573

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

By using a timer, a pop-up window can be made to behave like a

"topmost" window, a window that remains on top of all other windows

in the system. Such a window is brought to the top of all other

windows whenever a WM_TIMER message is sent to its window function.

NOTE: In Windows version 3.1, if you have a non-child window then the

extended window style WS_EX_TOPMOST is a better method for keeping it

topmost. CreateWindowEx() can create a window with the extended style and

SetWindowPos() can set or clear the style for a already created window.

MORE INFORMATION

================

To create a topmost window, first register a new window class. Using

that new class, create a pop-up window without a parent. The window is

created without a parent so that it is independent of the main

overlapped window created for each application in the system. This

will ensure that the topmost window remains open on the desktop even

if the main window is minimized.

After creating this pop-up window, create a timer with the SetTimer()

function and associate it with the window. Set the elapsed time to 100

milliseconds. The window function for the topmost window will process

the WM_TIMER message and call SetWindowPos() to place the topmost

window on top of all other windows. The code that processes the timer

message may be similar to the following:

   case WM_TIMER:

       GetWindowRect(hWnd, &rect);

       SetWindowPos(hWnd,

                    NULL,

                    rect.left,

                    rect.top,

                    0,

                    0,

                    SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);

       break;

The window coordinates returned by GetWindowRect() are used in the

call to SetWindowPos(). Doing this allows the user to move the topmost

window (if it has a caption bar) and it will remain on top.

The wFlags parameter for SetWindowPos() also contains the

SWP_NOACTIVATE flag. This is required so that the window can remain on

top without moving the focus to that window. Failing to do this will

disable all other applications in the system.

When the application that installed the topmost window is terminated,

the timer should be removed using the KillTimer() function. This call

can be placed in the processing of the WM_DESTROY message in the

topmost window's window procedure.

With this implementation, when a menu is activated, the screen will

flash as the menu is painted and then the topmost window is painted

over the menu. Menu selections can be made normally. However,

depending upon the topmost window's position, not all menu items will

be properly visible.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrTim


Preventing an MDI Child Window from Changing Size

Article ID: Q71669

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In an application using the Windows multiple document interface (MDI), MDI

child windows are always created with a maximize button, a minimize button,

and a thick "sizing" border. Currently, it is not possible to modify this

default behavior.

However, it is possible to prevent an MDI child from being maximized,

minimized, or sized. This can be done by performing two steps:

1. Disable the Maximize, Minimize, and Size options on the child

   window's system menu.

2. Trap the appropriate WM_SYSCOMMAND messages in the MDI child

   window's window procedure.

This article contains a sample MDI child window procedure that

illustrates this technique.

MORE INFORMATION

================

The following sample MDI child window procedure can be used to

implement an MDI child that can not be maximized, minimized or sized:

LONG FAR PASCAL SampleMDIChildWndProc(hWnd, msg, wParam, lParam)

HWND    hWnd;

WORD    msg;

WORD    wParam;

LONG    lParam;

// This sample MDI child window procedure can be used to prevent the

// MDI child from being maximized, minimized, or sized.

//

// Note that the child will still have a maximize button, a minimize

// button, and a thick "sizing" border. Currently, there is no way to

// prevent Windows from creating MDI children with these default

// styles.

//

// We can, however, disable the maximizing, minimizing, and sizing

// functionality by:

//

// 1. Disabling system menu options

// 2. Trapping WM_SYSCOMMAND messages

{

    HMENU    hSystemMenu;    // the MDI child's system menu

    switch (msg)

        {

    case WM_INITMENU:

        // Disable and gray the Maximize, Minimize, and Size items

        // on the MDI child's system menu

        hSystemMenu = GetSystemMenu(hWnd, FALSE);

        EnableMenuItem(hSystemMenu, SC_MAXIMIZE, MF_GRAYED |

             MF_BYCOMMAND);

        EnableMenuItem(hSystemMenu, SC_MINIMIZE, MF_GRAYED |

             MF_BYCOMMAND);

        EnableMenuItem(hSystemMenu, SC_SIZE, MF_GRAYED |

             MF_BYCOMMAND);

        break;

    case WM_SYSCOMMAND:

        // "Eat" these system commands to disable maximizing,

        // minimizing, and sizing functionality.

        // Note that wParam must be combined with 0xFFF0, using

        // the C bitwise AND (&) operator, when processing

        // the WM_SYSCOMMAND message.

        switch (wParam & 0xFFF0)

            {

        case SC_MAXIMIZE:

        case SC_MINIMIZE:

        case SC_SIZE:

             return 1L;

        default:

             break;

            }

        break;

    default:

        break;

        }

    return DefMDIChildProc(hWnd, msg, wParam, lParam);

}

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMdi


Context-Sensitive Help in a Dialog Box Through F1

Article ID: Q72219

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In an application developed with Windows version 3.0 and later, to

implement the ability to request context-sensitive help by pressing the F1

key in a dialog box, it is necessary to install a message filter.

This article describes the details of installing the message filter. In

particular, it describes code that could be added to the Generic sample

application (included with the Windows Software Development Kit) to install

a message filter that would detect F1 keystrokes in the About Generic modal

dialog box.

MORE INFORMATION

================

Detecting F1 Keystrokes in a Dialog Box

---------------------------------------

Normally, the child control windows in a dialog box do not pass keystroke

messages on to the dialog box window. To detect F1 keystrokes in a dialog

box, it is necessary to install a message filter.

Installing a Filter Function

----------------------------

Page 1-65 of the "Microsoft Windows Software Development Kit Reference,

Volume 1" for version 3.0 of the Windows SDK and page 70 of "Programmer's

Reference, Volume 1, Overview" for version 3.1 of the Windows SDK describe

the method for installing a filter function for Windows.

Sample Code

-----------

Perform the following six steps to add code to the Generic sample

application to provide context-sensitive help in the About Generic modal

dialog box:

1. Define a private message that the filter function can post to the

   application. For example:

   #define PM_CALLHELP  WM_USER+1000

                                  // wParam and lParam can be used to

                                  // pass context information

2. Define global variables:

   FARPROC lpfnFilterProc;        // Our filter function

   FARPROC lpfnOldHook;           // Previous filter function

                                  // in the chain

3. Add a filter function to the C-language source file. For example:

/*--------------------------    FilterFunc -------------------------*/

//

//   PARAMETERS:

//

//      nCode : Specifies the type of message being processed. It will

//              be either MSGF_DIALOGBOX, MSGF_MENU, or less than 0.

//

//      wParam: specifies a NULL value

//

//      lParam: a FAR pointer to a MSG structure

//

//

//   GLOBAL VARIABLES USED:

//

//      lpfnOldHook

//

//

//   NOTES:

//

//     If (nCode < 0), return DefHookProc IMMEDIATELY.

//

//     If (MSGF_DIALOGBOX==nCode), set the local variable ptrMsg to

//     point to the message structure. If this message is an F1

//     keystroke, ptrMsg->hwnd will contain the HWND for the dialog

//     control that the user wants help information on. Post a private

//     message to the application, then return 1L to indicate that

//     this message was handled.

//

//     When the application receives the private message, it can call

//     WinHelp. WinHelp must NOT be called directly from the

//     FilterFunc() routine.

//

//     In this example, post a private PM_CALLHELP message to the

//     dialog box. wParam and lParam can be used to pass context

//     information.

//

//     If the message is not an F1 keystroke, or if nCode is

//     MSGF_MENU, we return 0L to indicate that we did not process

//     this message.

//

//

DWORD FAR PASCAL FilterFunc(nCode, wParam, lParam)

int   nCode;

WORD  wParam;

DWORD lParam;

{

   MSG FAR * ptrMsg;

   if (nCode < 0)                         // MUST return DefHookProc

      return DefHookProc(nCode, wParam, lParam,

                           (FARPROC FAR *)&lpfnOldHook);

   if (MSGF_DIALOGBOX == nCode)

      {

      ptrMsg = (MSG FAR *)lParam;

      if ((WM_KEYDOWN == ptrMsg->message)

             && (VK_F1 == ptrMsg->wParam))

         {

         // Use PostMessage here to post an application-defined

         // message to the application. Here is one possible call:

         PostMessage(GetParent(ptrMsg->hwnd),

                                PM_CALLHELP, ptrMsg->hwnd, 0L);

         return 1L;                       // Handled it

         }

      else

         return 0L;                       // Did not handle it

      }

   else                                   // I.e., MSGF_MENU

      {

         return 0L;                       // Did not handle it

      }

}

/*--------------------- end FilterFunc  ----------------------------*/

   Note that FilterFunc() returns a DWORD. The documentation in volume 1

   of the SDK reference volume 1 that indicates that a filter function

   should return an integer is incorrect. Note also that not all

   messages are passed to DefHookProc(). The message hook is for this

   application only, so it is known that no other application needs to

   see these messages. However, DefHookProc() MUST be called when the

   nCode parameter is less than zero.

4. Export the filter function in the module definition file.

5. Before calling DialogBox(), set the hook. After DialogBox() returns,

   unhook the hook. For example, the About Generic dialog box could be

   called as follows:

   case IDM_ABOUT:

     lpProcAbout    = MakeProcInstance(About, hInst);

     lpfnFilterProc = MakeProcInstance(FilterFunc, hInst);

     lpfnOldHook    = SetWindowsHookEx(WH_MSGFILTER,

                                       lpfnFilterProc,

                                       hInst,

                                       NULL);

     DialogBox(hInst, "AboutBox", hWnd, lpProcAbout);

     UnhookWindowsHook(WH_MSGFILTER, lpfnFilterProc);

     FreeProcInstance(lpfnFilterProc);

     FreeProcInstance(lpProcAbout);

     break;

6. Have the application respond to the private message by calling

   WinHelp.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Changing the Color of an Edit Control

Article ID: Q74043

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The source code fragment below demonstrates how to paint the foreground and

background of a single-line edit control in an application developed for

the Microsoft Windows graphical environment. It creates a window that

contains one single-line edit control and paints the edit control cyan on

blue.

Windows sends the WM_CTLCOLOR message to the parent of an edit control

before the control is painted. If desired, the parent window, usually

a dialog box procedure, can process this message and change the text

and background colors of the control.

NOTE: WM_CTRLCOLOR is obsolete on Windows NT and Windows 95. Instead, you

would use WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLOREDIT,

WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, or

WM_CTLCOLORSTATIC.

MORE INFORMATION

================

The following MainWndProc demonstrates WM_CTLCOLOR processing:

long FAR PASCAL MainWndProc(HWND hwnd, unsigned msg,

                            WORD wParam, LONG lParam)

{

static   HWND     hwndEdit;

static   HBRUSH   hBrush;

   switch (msg)

   {

      case WM_CREATE:

         {

            HDC hdc;

            TEXTMETRIC tm;

            hdc = GetDC(hwnd);

            GetTextMetrics(hdc, &tm);

            ReleaseDC(hwnd, hdc);

            hwndEdit = CreateWindow("edit", NULL,

                            WS_CHILD | WS_VISIBLE

                            | ES_AUTOHSCROLL | ES_MULTILINE,

                            10, 20, 100, tm.tmHeight,

                            hwnd, 1, hInst, NULL);

            // Create a blue brush to be used for the edit control's

            // background color.

            hBrush = CreateSolidBrush(RGB(0, 0, 255));

         }

         break;

      case WM_CTLCOLOR:

      {

         // Set foreground and background colors only if this

         // is an edit control.

         if (HIWORD(lParam) == CTLCOLOR_EDIT)

         {

            // Set the edit control's foreground text color to

            // cyan and the text's background color to blue.

            SetTextColor(wParam, RGB(0, 255, 255));

            SetBkColor(wParam, RGB(0, 0, 255));

            // Properly originate the background brush. This is

            // of use if the brush is a pattern instead of a

            // solid color.

            UnrealizeObject(hBrush);

            SetBrushOrg(wParam, 0, 0);

            // Return a handle to the background brush for the edit

            // control.

            return (DWORD)hBrush;

         }

      }

      break;

      case WM_SETFOCUS:

         SetFocus(hwndEdit);

         return 0;

      case WM_DESTROY:

         PostQuitMessage(0);

         DeleteObject(hBrush);

         break;

   }

   return DefWindowProc(hwnd, msg, wParam, lParam);

}

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


Freeing Resources Used by a Multiline Edit Control

Article ID: Q74224

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

An application developed for the Microsoft Windows graphical

environment must explicitly free the resources that a multiline edit

control uses in the following two situations:

1. Before sending the edit control a EM_SETHANDLE message to change

   the text buffer, the application must first send a EM_GETHANDLE

   message to the control to obtain a handle to the existing buffer.

   When an application specifies a new text buffer, Windows does not

   automatically free the existing buffer. To prevent memory loss, the

   application must free the buffer by calling the LocalFree function.

2. If an application creates a font object and uses the WM_SETFONT

   message to specify that an edit control should use that font, the

   application must call the DeleteObject function to delete the font

   object when it is no longer needed.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


Size Limits for a Multiline Edit Control

Article ID: Q74225

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, the amount of text

that a user can enter into a multiline edit control is limited by the

number of characters the user can type into the edit control (set

using the EM_LIMITTEXT message) and by the size of the buffer the edit

control uses to hold the text.

In general, Windows edit controls were designed as vehicles into which

the user can enter and edit small amounts of text. They cannot be used

as large-scale text editors.

MORE INFORMATION

================

Initially, the user can enter a maximum of 30,000 bytes into a

multiline edit control. If the user attempts to enter more text, the

edit control beeps and does not accept the characters. An application

can set this limit to any value between 1 and 65,535 (0xFFFF)

characters by sending the edit control an EM_LIMITTEXT message.

A multiline edit control is also subject to the following limitations:

1. The maximum number of characters in a single line is 1024.

2. The maximum width of a line is 30,000 pixels.

3. The maximum number of lines is approximately 16,350.

By default, the edit control's text buffer is allocated from the

application's local heap. Windows can dynamically grow and shrink the

text buffer as the user enters text into and deletes text from the

edit control. The amount of text that can be edited is determined by

how large a buffer Windows can allocate from the local heap. Because

the heap shares the application's default data segment with many other

objects, the maximum size of the text buffer is likely to be

substantially smaller than 64K.

An application can specify a global text buffer for an edit control.

By using a global buffer, an edit control can store almost 64K of

data. The actual size limit of an edit control depends on the number

of lines stored in the edit control. Edit controls contain a

dynamically allocated buffer, which contains offsets into the text

buffer for each line. Because each line requires 2 bytes of storage,

the buffer grows as the number of lines in the edit control grows. In

addition to the buffer, there are slightly less than 100 bytes of

fixed overhead associated with an edit control. Windows does not

provide any built-in method to process a single block of more than 64K

of text.

One major drawback of using a global memory buffer is that the

EM_GETHANDLE and EM_SETHANDLE messages cannot be used to change the

memory used by the edit control.

For more information on using a global memory buffer, query the

Microsoft Knowledge Base on the following words:

   prod(winsdk) and GLBEDIT

Editing features such as Cut and Paste do not affect the amount of

text that can be edited because Windows uses global memory to

implement these features.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


Actions Prohibited in System Modal Dialog Boxes

Article ID: Q74332

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The following actions are not supported in a system modal dialog box

in the Microsoft Windows graphical environment:

1. Sending an intertask message

2. Changing the focus

3. Activating another application

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Killing the Parent of a Modal Dialog Box

Article ID: Q74474

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

An application cannot destroy the parent of a modal dialog box. When

the modal dialog box ends, control is returned to its parent. If the

parent is destroyed, control is given to a nonexistent window and the

application crashes.

When a parent window receives the destroy message, it is too late to

destroy a child modal dialog box. The destroyed dialog box does not

return control until after all the existing messages are processed,

including the final destruction of the parent window.

Therefore, it is imperative that all generational parents of a modal

dialog box be disabled and have no way of receiving a WM_DESTROY

message while the modal dialog box is active.

MORE INFORMATION

================

This situation does not affect modeless dialog boxes. Therefore, if

the design of a system cannot rule out the above problem, use a

modeless dialog box instead of a modal dialog box.

Because the Task Manager can kill any program at any time, there is no

absolute protection from the parent being closed. The optimal solution

is to forgo modal dialog boxes in favor of modeless dialog boxes.

When a modeless dialog box is created, it may disable its parental

windows.

Additional reference words: 3.00 3.10 wm_close

KBCategory: kbprg

KBSubcategory: UsrDlgs


Designing Applications for High Screen Resolutions

Article ID: Q74527

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Every day, the Microsoft Windows graphical environment is run at

greater screen resolutions and sizes with more colors. This article

outlines several guidelines to follow to ensure that an application

runs well on all video configurations.

MORE INFORMATION

================

Avoid the following three pitfalls:

1. Hard-coded screen sizes. The VGA 640 by 480 standard resolution

   screen will not be around forever. If more screen area lets the

   application display more data, let the window grow as big as the

   user demands. If screen dimensions are important to the

   application, use the GetSystemMetrics function with the SM_CXSCREEN

   and SM_CYSCREEN constants to obtain the screen size.

2. Scaling all screen output proportional to resolution. Many users

   prefer high screen resolutions for the extra screen "real estate"

   they allow, not just for improved readability.

3. Centering dialog boxes relative to the screen. On a very large,

   high-resolution monitor, many applications can run simultaneously

   without overlapping. Because users expect dialog boxes and

   notifications to appear near the main application window, position

   dialog boxes relative to the main application window.

Perform the following five steps:

1. Test the application at all screen sizes. Watch out for poorly

   scaled objects that may require fine-tuning, oversized windows, and

   hard-to-read fixed-size text.

2. Take advantage of leftover screen real estate. For example, if an

   application document does not require the full screen, allow users

   the option of filling the remaining space with multiple windows,

   toolbars and other controls, help information, and so forth.

3. Use scaled graphical screen resources where possible. If the

   application uses a toolbar, icons, pictures, and so forth, Windows

   metafiles are likely to be more versatile than bitmaps (although

   perhaps slower). Scaling based on screen resolution is more

   effective than scaling based on application window size.

4. Use the WM_GETMINMAXINFO message to help Windows decide how big the

   maximized application window needs to be. Maximizing a text editor

   application to the full 2048 x 2048 screen size is probably not

   useful. Maximizing an application at startup is particularly

   impolite.

5. Optimize window redraws. If a window contains a lot of information,

   try to redraw the entire window as infrequently as possible. Use

   the InvalidateRect function to coalesce window update regions into

   a single repaint. Even if there is not much to draw, many

   application windows may be open on a high-resolution screen.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrPnt


"Power-Friendly" Applications

Article ID: Q74528

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Power-managed personal computers, such as some battery-powered

notebook computers, are designed to conserve power during periods of

CPU inactivity or "idle time." Although most power-saving measures

should occur transparently to an application, developers should be

aware of several attributes that make an application "power friendly."

To qualify as "power-friendly," an application must use the

PeekMessage and Yield functions carefully, preferably only for

temporary background tasks. As long as an application is in a

PeekMessage loop, the Windows system cannot go idle. Therefore, an

application should not remain in a PeekMessage loop after its

background processing has completed.

MORE INFORMATION

================

Traditionally, an application running in the Windows multitasking

environment needed only to ensure that once it was finished with its

processing it yielded the processor to other applications in the

system. However, the increased popularity of battery-powered systems

imposes another responsibility on applications: to allow Windows to

"go idle" as often as possible.

To Windows, the system appears idle when all executing programs are

awaiting input. All applications have called the GetMessage or

WaitMessage function, and no pending messages are in any application

queue. At such times, the Windows kernel broadcasts an idle

notification by using an MS-DOS interrupt. A power-managed PC can use

this notification as a signal to take power-saving measures.

When an application is in a PeekMessage or Yield loop, it prevents

Windows from going idle, thus thwarting attempts by power-managed PCs

to save power.

An application's main message handler should use a GetMessage loop or

equivalent structure (such as the combined use of the PeekMessage and

WaitMessage functions) when no background processing is required. This

will allow Windows to go idle and power-saving measures to take

effect.

Applications that must periodically service a task (for example, a

communications connection) should poll, in response to a message from a

timer, if there is no other way to determine when the status of the

device changes.

Additional reference words: 3.00 3.10 APM

KBCategory: kbprg

KBSubcategory: UsrMsg


Drawing the Icon for a Minimized Application

Article ID: Q74539

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The text below describes how an application developed for the

Microsoft Windows graphical environment can draw its own icon when it

is minimized. An application can use these techniques to draw

different icons to indicate its state.

In Windows version 3.1, an application can initiate a dynamic data

exchange (DDE) conversation with the Windows Program Manager to

determine which icon the user has associated with an application and

can then draw that icon using the following techniques.

MORE INFORMATION

================

To draw its own icon when minimized, a Windows-based application performs

the following five steps:

1. When the application registers its main window's window class,

   specify NULL as the value of the hIcon member of the WNDCLASS data

   structure.

2. Create a static variable to store the icon the application will

   use, as follows:

      HICON hIcon;

   Initialize this variable to the value returned from the CreateIcon

   or LoadIcon function.

3. To draw the icon, process the WM_PAINT message in the main window's

   window procedure as follows:

   case WM_PAINT:

      {

      PAINTSTRUCT ps;

      if (IsIconic(hWnd))

         {

         BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);

         // Paint the desktop window background.

         DefWindowProc(hWnd, WM_ICONERASEBKGND, (WORD)ps.hdc, 0L);

         // Draw the icon on top of it.

         DrawIcon(ps.hdc, 0,0, hIcon);

         EndPaint(hWnd, (LPPAINTSTRUCT)&ps);

         }

      else

         return DefWindowProc(hWnd, message, wParam, lParam);

      }

4. To prevent a screen flash when the application draws the icon,

   process the WM_ERASEBKGND message in the main window's window

   procedure, as follows:

   case WM_ERASEBKGND:

      if (IsIconic(hWnd))

         // Do not erase the background now. When the application

         // paints its icon, it will erase the background.

         return TRUE;

      else

         return DefWindowProc(hWnd, message, wParam, lParam);

5. Process the WM_QUERYDRAGICON message in the main window's window

   procedure. When the user is about to drag a window that has no icon

   defined for its window class, Windows sends it a WM_QUERYDRAGICON

   message. The code below causes Windows to create a dragging cursor

   based on the specified icon. Windows automatically converts a color

   icon to a monochrome cursor.

   case WM_QUERYDRAGICON:

      return (LONG)(WORD)hIcon;

      break;

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Private Profile (INI) Files Not Designed as Database

Article ID: Q74602

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, a private profile or

initialization file, as the name suggests, is designed to be used when

a program initializes and terminates. A profile stores a limited

amount of information from one program session to the next. A profile

is are not designed to serve as a database.

MORE INFORMATION

================

Windows assumes that an INI file is not larger than 64K; file access

is not guaranteed beyond that point. Even if a text editor is used to

extend the file, Windows does not search for information past the 64K

boundary.

Also, Windows performs a linear search of INI files; therefore, the

longer the file becomes, the longer it takes to access an item at the

end of the file. Each time an application accesses an INI file,

Windows opens and closes the file which incurs additional overhead.

One alternative to using initialization files to store large amounts

of information is for the program to write to and maintain its own

files. This approach is faster, more flexible, and more reliable than

using profile for purposes for which it is not designed.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrIni


When to Use WIN.INI or a Private INI File

Article ID: Q74608

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

An application should use a private profile (INI) file to store

initialization information where possible rather than the main INI

file in Windows, WIN.INI. Profile files are not designed for use as a

database or a mass-storage device.

MORE INFORMATION

================

Applications use the profile functions in the Windows application

programming interface (API) to save and retrieve initialization

settings. The following profile functions are used with WIN.INI:

   GetProfileInt

   GetProfileString

   WriteProfileString

Until Windows version 3.0, applications stored their initialization

data in only one global place (WIN.INI). Windows version 3.0 added a

complimentary set of functions to the Windows API to enable an

application to store its initialization data in a private INI file.

These functions are as follows:

   GetPrivateProfileInt

   GetPrivateProfileString

   WritePrivateProfileString

The following factors provided the motivation for the addition of

private INI files:

 - INI files are limited to 64K in size.

 - Windows ignores the portion of INI files past 64K. Therefore, if

   enough applications use WIN.INI rather than separate, private INI

   files, some of the user's INI data may be ignored.

 - No consistent way exists for users to remove old, unneeded

   information from the WIN.INI file. Typically, when an application

   is removed from the system, the files are deleted from the

   application's directory. However, the corresponding information may

   not be deleted from WIN.INI. Alternately, if initialization data is

   stored in a private INI file in the application's directory or in a

   file with the application's name, the user is much more likely to

   delete the obsolete information.

 - Windows uses a linear search to find information in INI files.

   Therefore, smaller INI files provide faster performance.

By default, INI files are created in the Windows directory. However,

an application should always use a fully qualified path to a different

directory because the Windows system directory is a shared resource in

a Windows network setup.

Do not use the private profile functions with the WIN.INI file.

Windows caches a copy of WIN.INI and one private INI file. This

caching scheme may be confused if WIN.INI is altered using the private

profile functions.

Applications should use INI files conservatively. Use as few sections

and as few lines as possible. For example, do not save the coordinates

of a window individually, as follows:

   [window save pos]

   ul = 10

   ur = 10

   ll = 100

   lr = 100

Instead, use one line, as follows:

   [save_pos]

   window=10 10 100 100

This is a more efficient use of space and is much faster.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrIni


Adding Items to the System Menus of All Applications

Article ID: Q74695

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

ADMENU.ZIP is a code sample on the Software/Data library that demonstrates

adding new menu items to the system menus of all applications running under

Windows at a given time.

Download ADMENU.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ADMENU.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ADMENU.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ADMENU.EXE

MORE INFORMATION

================

ADMENUAPP adds two menu items to the system menu of each application

running under Windows. To do this, it uses two system-wide hooks: a

WH_GETMESSAGE hook and a WH_CALLWNDPROC hook. Both of these hooks are

implemented in ADMENULIB, a fixed-code DLL.

Whenever the WH_CALLWNDPROC hook function sees a WM_INITMENU message being

sent to a top-level window, it appends the two new menu items to that

window's system menu. The items are removed when the menu is closed.

The two menu items that are added appear as "New Menu Item 1" and "New Menu

Item 2." If the user selects one of these items, the WH_GETMESSAGE hook

procedure sees the resulting WM_COMMAND message and responds by posting a

private message to ADMENUAPP. ADMENUAPP handles the private message by

displaying a dialog box stating that one of the two added items was

selected.

For more information on adding menu items to another application's system

menu, please see the following article(s) in the Microsoft Knowledge Base:

ARTICLE-ID: Q72222

TITLE     : Appending Menu Items to Other Applications

Additional reference words: 3.00 3.10 softlib

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


Using PeekMessage() Loops in a Dialog Box

Article ID: Q74795

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version(s) 3.0 and 3.1

----------------------------------------------------------------------

When a modal dialog box is created, Windows uses its own message loop,

which is stored in USER. If the application takes responsibility for

processing messages [using a PeekMessage() loop], then IsDialogMessage()

must be used to pass appropriate messages to the dialog box.

The following code fragment demonstrates the correct technique:

  bFlag = TRUE;

  while ((bFlag) || (PeekMessage(&message, hDlg, 0, 0, PM_REMOVE)))

    {

    if (!IsDialogMessage(hDlg, &message))

      {

      TranslateMessage(&message);

      DispatchMessage(&message);

      }

    }

If technique is not used, accelerator keys in the dialog box will not

function properly.

For additional information on the proper use of PeekMessage() loops, please

see the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q67293

   TITLE     : Some CTRL Accelerator Keys Conflict with Edit Controls

   -or-

   ARTICLE-ID: Q108936

   TITLE     : Using a Dialog Box as the Main Window of an Application

Additional reference words: 3.10 3.00

KBCategory: kbprg

KBSubcategory: UsrMsg


Working Around the STRINGTABLE 255 Character Limit

Article ID: Q74800

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows STRINGTABLE resources are limited to 255 characters per string.

However, it is possible to work with longer strings using the technique

described in this article.

MORE INFORMATION

================

The following function, MyLoadString, will allow strings longer than 255

characters to be loaded. Using the exclamation mark ("!") to indicate that

a particular string is part of a longer whole is not required; any

character that does not otherwise start a string may be used for this

purpose. The string IDs used for pieces of the same string must be

consecutive.

MyLoadString(HANDLE hInst, WORD wID, LPSTR szBuf)

{

  int i, j;

  char szLoadedString[256];   // temporary buffer

  *szBuf = 0;

  do

    {

    LoadString(hInst, wID, szLoadedString, 255);

    if ('!' == *szLoadedString)

      {

      lstrcat(szBuf, (szLoadedString + 1));

      wID++;

      }

    else

      lstrcat(szBuf, szLoadedString);

    }

  while ('!' == *szLoadedString);

  return lstrlen(szBuf);

}

The RC file will take on a form resembling the following:

STRINGTABLE

BEGIN

  100, "!This is the first part of the string to be loaded,"

  101, "!this is the second part, "

  102, "and this is the third"

END

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrRsc


DBCS Support in Windows Versions 3.0 And 3.1

Article ID: Q75255

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

In a version of Windows that is enabled for double-byte character sets

(DBCS), all functions that take strings as arguments will work with

strings of double-byte characters. In addition, any version of Windows

that supports DBCS will support the IsDBCSLeadByte function. This

function determines whether or not a byte is the leading byte of a

2-byte character. The Windows functions that use a string length

parameter (like lstrlen and TextOut) will use a count of bytes,

not of characters. The functions IsDBCSLeadByte, AnsiPrev, and

AnsiNext should be used to access characters within a string.

Note that DBCS-enabled Windows will typically have special methods to

enter double-byte or composite characters. Composite character

creation involves pressing several keys in a specified sequence to

form new characters. The entry system is integrated into Windows by

the original equipment manufacturer (hardware OEM). These characters

are not typically directly entered into an edit control. Composite

characters may be entered at the bottom of dialog box (as in OS/2). In

many systems, these characters are composed at the bottom of the

screen (in the composition window).

Copies of Windows version 3.0 developed for the United States and

Europe do not support DBCS. Copies of Windows version 3.1 developed

for the United States and Europe, and the KANJI adaptation of Windows

version 3.0 and 3.1 do support DBCS. The KANJI adaptation of Windows is

distributed through hardware OEMs. For more information on KANJI

Windows, search this knowledge base on the following words:

   KANJI

The March, 1990, "Microsoft Systems Journal" article "Using the OS/2

National Language Support Services to Write International Programs"

has more information on both DBCS and KANJI. It can be found in the

Software/Data Library by searching on OS2NLS or S12547. OS2NLS was

archived using the PKware file-compression utility.

Additional reference words: 3.00 3.10 softlib

KBCategory: kbprg kbfile

KBSubcategory: UsrLoc WintlDev


Program Manager Restrictions Settings

Article ID: Q75337

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

In Windows version 3.1, a new section will be added to the PROGMAN.INI

initialization file to allow system and network administrators to

restrict the functionality of the Program Manager to make it better

suited to handle shared files.

There are five new options available to prevent a user from modifying

his group's configuration or from running untrusted software. These

options appear in the section labeled [Restrictions]. This article

details each of the options below.

MORE INFORMATION

================

   [Restrictions]

   NoRun=[0/1]

      When the NoRun switch is set to 1, the Run command on the File

      menu is disabled. The default value of this option is 0 (allow

      File Run).

   [Restrictions]

   NoClose=[0/1]

      When the NoClose option is set to 1, this option prevents the

      user from exiting the Program Manager, through the File menu,

      the System menu, the ALT+F4 accelerator or the Task Manager. The

      default value of this option is 0 (allow exit).

   [Restrictions]

   NoSaveSettings=[0/1]

      When the NoSaveSettings option is set to 1, this option prevents

      the user from saving the main window position and the load order

      of the groups. It also disables the "Save Settings on Exit"

      command on the Options menu. The default value of this option is

      0 (allow the user to save settings).

   [Restrictions]

   NoFileMenu=[0/1]

      When the NoFileMenu option is set to 1, this option disables the

      File menu entirely. All commands on this menu are disabled as

      well. The default value of this option is 0 (the File menu is

      enabled).

   [Restrictions]

   EditLevel=<value>

      This EditLevel option controls the extend to which a user can

      modify read/write groups (shared, read-only groups may never be

      modified). The following values are recognized:

         0 Allow any change (default)

         1 User cannot create, delete, or rename groups

         2 Value 1 restrictions; also, user cannot create or delete

           items

         3 Value 2 restrictions; also, user cannot change item command

           lines

         4 Value 3 restrictions; also, user cannot change any item

           property

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrIni


Tips for Writing DBCS-Compatible Applications

Article ID: Q75439

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

String operations in systems that use a double-byte character set

(DBCS) are slightly different from a single-byte character system.

This article provides guidelines to reduce the work necessary to port

an application written for a single-byte system to a DBCS system.

MORE INFORMATION

================

In a double-byte character set, some characters require two bytes,

while some require only one byte. The language driver can distinguish

between these two types of characters by designating some characters

as "lead bytes." A lead byte will be followed by another byte (a "tail

byte") to create a double-byte character (DBC). The set of lead bytes

is different for each language. Lead bytes are always guaranteed to be

extended characters; no 7-bit ASCII characters can be lead bytes. The

tail byte may be any byte except a NULL byte. The end of a string is

always defined as the first NULL byte in the string. Lead bytes are

legal tail bytes; the only way to tell if a byte is acting as a lead

byte is from the context.

The Windows Software Development Kit (SDK) version 3.0 includes two

functions for moving through strings that may contain DBCs: AnsiNext()

and AnsiPrev(). The AnsiPrev() function is a time expensive call

because it must run through the string from the beginning to determine

where the previous character begins. It is best to search for

characters from the beginning rather than the end of a string.

The Windows SDK version 3.1 includes the IsDBCSLeadByte() function,

which returns TRUE if and only if the byte CAN BE a lead byte. Because

this function takes a char parameter, it cannot report if the byte IS

a lead byte (to do so would require context).

To make non-DBCS code run as quickly as possible, a source file may

use "#ifdef DBCS" around code that is only for DBCS, and compile two

versions of the object (OBJ) file. For example:

#ifdef DBCS

  for (pszTemp = szString; *pszTemp; pszTemp = AnsiNext(pszTemp))

#else

  for (pszTemp = szString; *pszTemp; ++pszTemp)

#endif

   ...

To make the code easier to read, an application could define macros

for the AnsiNext() and AnsiPrev() functions if DBCS is not defined:

#ifndef DBCS

#define AnsiNext(x) ((x)+1)

#define AnsiPrev(y, x) ((x)-1)

#ifdef WIN31

#define IsDBCSLeadByte(x) (FALSE)

#endif

#endif

With these definitions in place, all of the code can be written for

DBCS. Note that the AnsiNext() function will not go past the end of a

string and the AnsiPrev() function will not go past the beginning of a

string, while the macros will. In addition, because the "y" parameter

in the AnsiPrev() macro is ignored, some code will give different

results when compiled with and without DBCS defined. The following

code is an example of this phenomenon:

   pszEnd = AnsiPrev(++pszStart, pszEnd);

The following code demonstrates how to find the offset of the filename

in a full path name:

LPSTR GetFilePtr(LPSTR lpszFullPath)

{

    LPSTR lpszFileName;

    for (lpszFileName = lpszFullPath; *lpszFullPath;

               lpszFullPath = AnsiNext(lpszFullPath))

        if (*lpszFullPath == ':' || *lpszFullPath == '\\')

            lpszFileName = lpszFullPath + 1;

    return lpszFileName;

}

Note that ':' and '\\' are guaranteed not to be lead bytes. The search

started from the beginning of the string rather than the end to avoid

using the AnsiPrev() function.

The following code demonstrates a string copy into a limited size

buffer. Note that it ensures that the string does not end with a lead

byte.

int StrCpyN(LPSTR lpszDst, LPSTR lpszSrc, unsigned int wLen)

{

    LPSTR lpEnd;

    char cTemp;

    // account for the terminating NULL

    --wLen;

    for (lpEnd = lpszSrc; *lpEnd && (lpEnd - lpszSrc) < wLen;

               lpEnd = AnsiNext(lpEnd))

        ;  // scan to the end of string, or wLen bytes

    // The following can happen only if lpszSrc[wLen-1] is a lead

    // byte, in which case do not include the previous DBC in the copy.

    if (lpEnd - lpszSrc > wLen)

        lpEnd -= 2;

    // Terminate the source string and call lstrcpy.

    cTemp = *lpEnd;

    *lpEnd = '\0';

    lstrcpy(lpszDst, lpszSrc);

    *lpEnd = cTemp;

}

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrLoc WintlDev


Altering Edit Control Strings in Place May Cause UAE

Article ID: Q75500

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Declaring an Edit control with certain styles, and altering the text, may

have undesirable effects. Depending upon whether or not pointers to the

text are passed to other functions, changing the text in place may generate

an unrecoverable application error (UAE).

Declaring an Edit control with any of the following styles, ES_LOWERCASE,

ES_UPPERCASE, or ES_OEMCONVERT, and calling either SetWindowText (hEdt,

lpstr) or SetDlgItemText (hDlg, editID, lpstr) will alter the string in

place. Calling either one of the above mentioned functions to alter a

string contained in a code segment, which is labeled PURE in the

corresponding .DEF file, will result in a UAE.

Additional reference words: 3.00 3.10 controls strings

KBCategory: kbprg

KBSubcategory: UsrCtl


Ending the Windows Session from an Application

Article ID: Q75629

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The ExitWindows() function permits an application to terminate Windows.

ExitWindows() restarts Windows by using the EW_RESTARTWINDOWS flag, and

exits Windows and reboots the system by using the EW_REBOOTSYSTEM flag.

These constants are consistent for the Win16 application programming

interface (API), the Win32 API under Windows NT and Win32s.

All applications are sent the WM_QUERYENDSESSION message notifying them

that a request has been made to restart or terminate Windows. If all

applications "agree" to terminate, Windows will then send the WM_ENDSESSION

message to all applications before terminating.

In addition, you can use the ExitWindowsEx() function to terminate

Windows. It runs a specified MS-DOS-based application and then restarts

Windows. It takes two parameters:

 - A null-terminated string that specifies the path and filename of the

   executable MS-DOS file to run after terminating Windows.

 - A null-terminated string that specifies any parameters for the MS-DOS

   executable file. This value can be NULL.

The ExitWindowsExec() function is typically used by installation programs

to replace Windows components (device drivers, system DLL's, and so on)

that are active when Windows is running.

MORE INFORMATION

================

In previous versions of Windows, an application sent the WM_ENDSESSION

message to all windows to close the Windows session. Starting with version

3.0, ExitWindows() puts Windows into a special state so that Windows can

perform housekeeping and unhook system interrupts to cleanly exit to

MS-DOS. Because an application cannot simulate this Windows special state,

the application must call the ExitWindows() function to close Windows.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


XLTABLE Clipboard Format Documentation Available

Article ID: Q75631

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

XLTABLE is a new clipboard format developed for use in dynamic-data

exchange (DDE) conversations with Microsoft Excel.

Using this format instead of BIFF (the Binary Interchange File Format)

results in faster conversations. Code to read and write this format is

also easier to implement. The format does not introduce translation

problems that can occur when putting text on the clipboard.

The "Microsoft Excel Software Development Kit," part number 065-000-

020, describes all the Excel file formats. In the United States, this

document is available for $20.00 through the Microsoft Consultant

Relations Program by calling (800) 227-4679. Outside the United

States, contact the Microsoft subsidiary that supports your country

for pricing and availability information.

MORE INFORMATION

================

The following information documents the XLTABLE data format:

FAST FILE FORMAT

----------------

The Fast DDE Table data consists of multiple simple_datablocks, one

after the other:

   Fast_DDE_Table = <simple_datablock> <simple_datablock> ...

       <simple_datablock>

A simple_datablock has three parts:

    WORD tdt;       // The table datatype

    WORD cb;        // The size (in bytes) of the data part

    BYTE data[];    // There are cb bytes in this part

Description of the Table Datatypes:

tdt         Value    Meaning

---         -----    -------

tdtTable    0x0010   Gives the size of the table. The cb is 4.

                     The data (4 bytes) has two words: the first

                     word is the number of rows, the second word

                     is the number of columns.

tdtFloat    0x0001   The data contains floating point values in IEEE

                     real format. The size of each entry is 8 bytes.

tdtString   0x0002   The data contains strings in "st" format. In this

                     format, the first byte gives the length of the

                     string, and the following bytes make up the

                     string. The string is not null-terminated.

tdtBool     0x0003   Boolean values: 1 = TRUE, 0 = FALSE

                     Each entry is 2 bytes.

tdtError    0x0004   Error values for the cell:

                         0  = #NULL!

                         7  = #DIV/0!

                         15 = #VALUE!

                         23 = #REF!

                         29 = #NAME?

                         36 = #NUM!

                         42 = #N/A

                     Each entry is 2 bytes.

tdtBlank    0x0005   The cb is 2. The data (2 bytes) has one word.

                     The value of the word is the number of blank cells.

tdtType     0x0080   Not used. Gives the type of the cell. Each entry

                     is 2 bytes.

tdtFormat   0x0081   Not used. Gives the format of the cell (0-

                     relative index into the format table as shown in

                     the Format Number dialog box). Each entry is 2

                     bytes.

Order of the cells: The first simple_datablock must be of type

tdtTable. This record provides the number of rows and columns. This is

followed by rows*cols cells represented by the subsequent

simple_datablocks. The cells are represented row-wise, (all cells of

the first row are listed first, then all cells of the second row, and

so on).

For example, the Fast DDE Table for a selection consisting of three

cells in a row, containing the strings "East", "West", and "North",

respectively, will resemble the following:

   10 00 04 00 01 00 03 00    - tdtTable, 4, 1, 3

   02 00 10 00                - tdtString, 16

      04 45 61 73 74          - 4, East

      04 57 65 73 74          - 4, West

      05 4e 6f 72 74 68       - 5, North

Additional reference words: 3.00 3.10 DDE clipboard

KBCategory: kbprg

KBSubcategory: UsrClp


Guidelines for Allocating Instance (Per-Window) Data

Article ID: Q76103

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

If an application creates multiple windows of a single window class,

that application must carefully manage data for those windows.

Undesired results may occur when windows share the same global data

because modifications of that data will affect all windows.

If an application has a window that normally relies on global data and

the application creates multiple instances of that window, whatever

was kept in global data must be kept in instanced data. The optimal

method is to store a private data structure in global or local memory

and to store a handle to that memory in the window's so-called "extra"

bytes. Alternatively, the window may store the handle in its property

list.

This article discusses the concerns and methods for storing extra data

with windows using both window extra bytes and property lists.

MORE INFORMATION

================

1. Application and Window Instances, Sharing Data

-------------------------------------------------

The word "instance" usually refers to a particular copy of an

application that is currently running in the system. The term

"instance" means "copy of data"; each instance of an application has a

separate data segment containing global and static data, the

application's stack, and the application's local heap. Different

instances of the same application have only very limited access to

each other's data (through the use of the GetInstanceData

function).

Every window is an "instance" of a particular window class. A window

is represented by a data structure allocated from USER's local heap

(identified by hWnd) that contains information specific to that

window, such as its window style, and a pointer to its window

procedure. Since multiple windows of the same class may reside in the

same application instance and share the same window procedure, those

windows freely share all global data in the application's data

segment. Therefore, a particular window should never depend on a

global variable.

Consider a case in a text editing program based on the Windows

multiple document interface (MDI) where each MDI child window

maintains information about the file being edited in that window. If

each window uses the same global variables to store page numbers, file

names, and text length, only one window would display correct

information. As soon as the user loads another file or performs an

operation that changes any global variable, all windows are affected.

The effects may not be apparent until a repaint occurs on the other

windows, making the problem extremely difficult to track down. To

avoid this situation, keep any window-specific data separately

attached to each window class, isolating that data. Such data may be

stored either in window extra bytes or property lists. The most

efficient and fastest method is to allocate extra memory for data, and

store that memory handle in window extra bytes. Property lists are

most useful when dealing with preregistered window classes or with

temporary data.

2. Window Extra Bytes and Extra Allocations

-------------------------------------------

An application specifies window extra bytes for a class in the

cbWndExtra field of the WNDCLASS structure prior to calling the

RegisterClass function. Windows allocates these bytes from USER's

local heap in addition to the window's data structure. An application

reads these extra bytes with the GetWindowWord and GetWindowLong

functions and modifies them with the SetWindowWord and

SetWindowLong functions.

Extra bytes are a very scarce resource because they reside in USER's

local heap, and therefore reduce available system resources. Always

minimize an application's use of window extra bytes as much as

possible.

There is a myth that the GetWindowWord and GetWindowLong calls are

extremely fast, which serves as an excuse to use a large number of

window extra bytes. While these functions are highly optimized, they

still need to perform necessary checks on the window handle and trap

special cases. They do more than a simple lookup in USER's heap, and

both require a far call. Only when an application requires a single

WORD or DWORD should it store that data directly in extra bytes.

The most efficient method for allocating more than 4 extra bytes is to

declare a single HANDLE in the window's extra bytes, allocate an

additional data structure when creating the window, and store that

handle in the window extra bytes. This method minimizes the use of

extra bytes and provides very fast access to the entire data

structure. If the data is allocated as local FIXED memory, there is no

need to even lock the data before using it.

The best time to allocate this memory is while processing the

WM_NCCREATE message; a window receives this message only once, very

soon after creation. The code to perform this allocation might

resemble the following:

   case WM_NCCREATE:

       pExtraData=(typecast)LocalAlloc(LPTR, cbData);

       SetWindowWord(hWnd, 0, (WORD)pExtraData);

       break;

Here, cbData is the number of bytes in the extra data structure, and

the LPTR parameter to the LocalAlloc function specifies the

LMEM_FIXED and LMEM_ZEROINIT flags. Use the number 0 as the index

for the SetWindowWord call because 0 references the start of the

extra bytes. Note also that (typecast) is a placeholder for the

appropriate pointer type of the data structure.

The best time to free this memory is while processing the WM_NCDESTROY

message. The code to perform this step might resemble the following:

    case WM_NCDESTROY:

        pExtraData=GetWindowWord(hWnd, 0);

        if ((typecast)NULL!=pExtraData)

            {

            //Clean out the old handle.

            SetWindowWord(hWnd, 0, 0);

            LocalFree((HANDLE)pExtraData);

            }

        break;

2.1 Using Extra Data in the Window Procedure

--------------------------------------------

To access the extra data stored in separately allocated memory, a

window must retrieve a pointer to the data before processing any

message that requires that data.

If the application allocated memory as LMEM_FIXED, retrieving a

pointer to the extra data structure requires only a single call to

GetWindowWord, as follows:

   pExtraData=(typecast)GetWindowWord(hWnd, 0);

From this point on, accessing ANY field in the data structure is

extremely fast because it requires only a dereference operation on the

pointer. The following is a sample reference of the extra data:

   if (0==pExtraData->cMouseMoves)

       {

       ...

       }

The main advantage of this method over extended use of window extra

bytes is that it uses only a single call to GetWindowWord and

SetWindowWord functions to read and write ANY data in the entire

data structure. Many calls to the GetWindowWord and SetWindowWord

functions are necessary if this structure was stored entirely

in extra bytes (unless the structure itself is only 2 bytes long).

In addition, maintaining the data structure is much easier when it is

defined as a C structure and not as a large group of offsets for the

GetWindowWord and SetWindowWord functions. Maintaining offsets

requires carefully defining constants based on the sizes of the data

types involved, and defining reasonably symbolic names to keep the

source code readable. Defining a C structure is much easier and lets

the C compiler determine the size of each field.

2.2 Local Versus Global Memory

------------------------------

Local memory from the application's heap is best suited for the

purposes of instanced data, unless heap space is already a scarce

commodity. Local allocations are very inexpensive as far as system

memory is concerned. In addition, handles to local memory allocated

with LMEM_FIXED are directly usable as near pointers.

In Windows version 3.x, each global allocation (through the

GlobalAlloc function) uses a selector from the local descriptor

table (LDT). Only 8192 are selectors available in Windows version 3.x

enhanced mode and only 4096 are available in Windows 3.x standard

mode. If an application creates hundreds of instances of a window

that allocates a global segment, it will unnecessarily deplete the

number of free selectors available to all applications in the system.

For more information on using selectors, please query on the

following words in the Microsoft Knowledge Base:

   prod(winsdk) and protect mode and handle limits

An application can conserve global handles by allocating a large block

of memory and performing local allocations within the block. This

technique, known as multiple FAR heaps, is described in Chapter 18 of

the book titled "Windows 3.0 Power Programming Techniques" by

Paul Yao and Peter Norton (Bantam Computer Books). Another good

reference is the article "Improve Windows-Based App's Memory Use

with Subsegment Allocation and Custom Resources" in the January 1991

issue of the "Microsoft Systems Journal" (volume 6, number 1).

3. Properties

-------------

Properties allow an application to attach extra data to ANY window and

do not require the application to process any messages for that window

or modify the window's data in any way. An application attaches,

retrieves, and deletes properties through the SetProp, GetProp,

and RemoveProp functions, respectively.

Properties are most useful when an application needs to attach data to

any of Windows's predefined classes, such as dialog boxes and

controls, because such windows have no extra bytes available for

application use. Properties are also very useful for temporary data

that needs to be attached to a window for only a portion of that

window's lifetime.

Using properties is relatively slow and has the added penalty that

each property is limited to a WORD (which is very inconvenient for

large structures). They also use space in the USER's local heap, and

therefore consume valuable system resources. Follow the same

guidelines for properties as for windows extra bytes, that is,

allocate extra memory and store the handle as a single property.

If the application may use extensive properties for dialog boxes or

standard Windows controls, consider one of the alternatives described

below.

3.1 Alternatives to Property Lists for Dialog Boxes

---------------------------------------------------

If an application needs to attach data to a dialog box, consider using

a private dialog class. The application registers this class and

provides a window procedure similar to the way it would for any other

type of application-specific window. A private dialog class requires

at least DLGWINDOWEXTRA window extra bytes; the application must add

DLGWINDOWEXTRA to any additional space for a memory handle. The extra

memory can be allocated and freed using the same messages described in

Section 2 above. Note that the offset of the memory handle for the

GetWindowWord and SetWindowWord  functions is DLGWINDOWEXTRA

instead of 0 (zero).

For more information on private dialog classes, please query on the

following words in the Microsoft Knowledge Base:

   prod(winsdk) and defdlgproc

3.2 Alternatives to Property Lists for Predefined Control Windows

-----------------------------------------------------------------

Most of Windows's predefined controls already use some number of

window extra bytes however they do not reserve any space for

application-specific use. An application can, however, create a

superclass and specify space for a HANDLE to extra data.

Superclassing is the process of retrieving a window's class

information, modifying the appropriate fields, and registering the new

class under a different name. The following six steps are involved in

this process:

1. Call the GetClassInfo function using the hWnd of an existing

   window of the class to superclass. This fills a WNDCLASS structure

   with information for that class.

2. Change the hInstance field of the WNDCLASS structure to the

   hInstance of the application.

3. Save the old lpfnWndProc value and store the address of the

   superclass procedure in that field. Class extra bytes are a

   suitable place to save the old value.

   Pass all messages not processed by the superclass procedure to this

   original lpfnWndProc and be sure to export the superclass procedure.

4. Save the value of cbWndExtra (again, class extra bytes are suitable

   for this purpose) and add sizeof(HANDLE) to that field. Do NOT

   simply store sizeof(HANDLE) or the control will break. The

   superclass MUST use the existing value of cbWndExtra as the offset

   to GetWindowWord and SetWindowWord functions when manipulating

   the extra memory handle.

5. Change the class name to something unique. Windows will not

   reregister a class if one already exists by that name.

6. Call the RegisterClass function with the new WNDCLASS structure.

Allocate extra memory for windows of this superclass using the same

method described above in Section 2.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Creating a Progress Dialog with a Cancel Option

Article ID: Q76415

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following article describes the mechanisms necessary to implement

a progress or activity indicator with a "Cancel Operation" option, to

be used for lengthy and CPU-intensive subtasks of an application.

Examples of operations using this include: copying multiple files,

directory searches, or printing large files.

MORE INFORMATION

================

The progress dialog is implemented in two steps:

1. Initialize the dialog before starting lengthy or CPU intensive

   subtask.

2. After each unit of the subtask is complete, call ProgressYield()

   to determine if the user has canceled the operation and to update

   the progress or activity indicator.

This is the description of the progress dialog procedure. The

procedure uses a global variable (Cancel) to inform the CPU-intensive

subtask that the user has indicated a desire to terminate the subtask.

WORD Cancel = FALSE;    /* This must be global to all modules */

                        /* which call ProgressYield()         */

BOOL FAR PASCAL ProgressDlgProc(hDlg, message, wParam, lParam)

HWND hDlg;

unsigned message;

WORD wParam;

DWORD lParam;

{

   switch (message)

      {

      .

      /* Use other messages to update the progress or activity */

      /* indicator.                                             */

      .

      case WM_COMMAND:

         switch (wParam)

            {

            case ID_CANCEL:    /* ID_CANCEL = 2 */

               Cancel = TRUE;

            default:

               return FALSE;

            }

      .

      .

      default:

         return FALSE;

      }

}

The following describes the ProgressYield procedure, which should be

called after each unit of the CPU-intensive subtask is completed. The

ProgressYield procedure uses the IsDialogMessage function (described

in the "Microsoft Windows Software Development Kit Reference Volume

1"). IsDialogMessage will convert keyboard messages into selection

commands for the corresponding dialog box as outlined in Table 1.7

beginning on page 1-51.

void ProgressYield(HWND hwnd)

{

   MSG   msg;

   /* Remove all available messages for any window that belong */

   /* to the current application.                               */

   while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

      {

      /* Translate and Dispatch the given message if the window */

      /* handle is null or the given message is not for the    */

      /* modeless dialog box hwnd.                             */

      if (!hwnd || !IsDialogMessage(hwnd, &msg))

         {

         TranslateMessage(&msg);

         DispatchMessage(&msg);

         }

      }

}

The following describes how to incorporate the progress dialog as part

of an application's subtask that is CPU-intensive. The PROGRESS_DLG

resource should contain a button with an ID of 2, because this is the

wParam of the WM_COMMAND that will be sent when the user presses the

ESC key. The button should also have the BS_DEFPUSHBUTTON style so

that the ENTER key will also result in the termination of the

CPU-intensive subtask.

   FARPROC lpProgressProc;

   HWND    hwndProgress;            /* This needs to be global if */

                                    /* accessed by other modules.  */

   .

   .

   /* Initialize before starting CPU-intensive work.               */

   lpProgressProc = MakeProcInstance(ProgressDlgProc,

                                     hInst);  /* Current instance. */

   hwndProgress = CreateDialog(hInst,         /* Current instance. */

                              "PROGRESS_DLG", /* Resource.         */

                              hwndParent,     /* Parent handle.    */

                              lpProgressProc);/* Instance address. */

   ShowWindow(hwndProgress);

   .

   .

   /* Start CPU intensive work here. */

      .

      .

      /* Before or after each unit of work, the application */

      /* should do the following:                           */

      ProgressYield(hwndProgress);

      if (Cancel == TRUE)

         break;   /* Terminate CPU-intensive work immediately. */

      .

      .

   /* End CPU-intensive work here. */

   .

   .

   DestroyWindow(hwndProgress);

   FreeProcInstance(lpProgressProc);

   .

   .

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Different Ways to Close an Application Under Windows

Article ID: Q77135

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, an application can

close in two different ways. The first method involves the user

closing the application, which includes choosing a menu item, double-

clicking the application's system menu, or choosing End Task in the

Windows Task Manager. The second method involves the user ending the

Windows session in the active shell program (either Program Manager or

File Manager).

In these two methods, the application receives different sets of

messages. If an application must perform certain operations before it

can exit properly, it must process the messages associated with each

method. This article discusses these messages and how to process them.

MORE INFORMATION

================

Method 1

--------

The three sets of actions below are facets of the first method above:

1. When the user double-clicks the application's system menu or

   chooses Close from the system menu, Windows sends a WM_SYSCOMMAND

   message to the application with wParam set to SC_CLOSE. If the

   user enters the ALT+F4 accelerator for Close, Windows posts the

   WM_SYSCOMMAND message to the application. If the application passes

   the WM_SYSCOMMAND message to DefWindowProc, the application

   receives a WM_CLOSE message.

2. If the user chooses End Task in the Windows Task Manager, the Task

   Manager posts a WM_CLOSE message to the application's main window.

3. If the application has an Exit option on its File menu, it should

   be coded to generate a WM_CLOSE message.

When an application receives a WM_CLOSE message, it must determine

whether the user has modified any files without saving the changes. If

so, the application must inform the user that changes have not been

saved and provide an opportunity to save the files, to close the

application without saving the files, or to cancel the application

termination request.

If the application is to close, it must call the DestroyWindow

function to destroy the main window. If the user is not ready to close

the application, the application must not pass the WM_CLOSE to

DefWindowProc because it will call DestroyWindow.

DestroyWindow recursively destroys all child windows of the main

window and all windows owned by the main window. If the application

has created windows that are neither children of nor owned by the main

window, the application must explicitly destroy these windows.

Method 2

--------

In the second method listed above, when the user ends the Windows

session from the active shell program (Program Manager or File

Manager), Windows sends a WM_QUERYENDSESSION message to all tasks in

the system. An application can process this message to determine when

the user terminates the Windows session. When an application receives

a WM_QUERYENDSESSION message, if files have been changed and the

changes have not been saved, the application must inform the user and

confirm the request to close the application. If the application

receives confirmation, it must return TRUE after processing the

WM_QUERYENDSESSION message. If the user does not confirm closing the

application, it must return FALSE to cancel closing Windows.

If any application cancels closing Windows in response to a

WM_QUERYENDSESSION message, Windows sends a WM_ENDSESSION message with

wParam set to FALSE for all applications. This informs each

application that the Windows session will continue.

If all applications return TRUE after processing the

WM_QUERYENDSESSION message, Windows sends each application a

WM_ENDSESSION message with wParam set to TRUE. This informs the

application that the current Windows session will end very shortly.

After the WM_ENDSESSION message, an application receives neither a

WM_CLOSE nor a WM_DESTROY message.

In summary, if an application must perform operations before it can

exit, such as saving files, the application must be prepared for both

the application close and Windows shutdown cases.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Retrieve Line Number from Edit Control Sample Code

Article ID: Q77782

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In an edit control, the EM_LINEFROMCHAR message returns the line

number of the line that contains a specified character.

EDITCNT is a file in the Microsoft Software Library that demonstrates using

the EM_LINEFROMCHAR message to determine the line number of the line

of an edit control selected using the mouse.

Download EDITCNT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EDITCNT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EDITCNT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EDITCNT.EXE

Additional reference words: 3.00 3.10 softlib EDITCNT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


Modifying the System Menu of an MDI Child Window

Article ID: Q77930

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The system menu of an MDI child can be modified only after the WM_CREATE

message for the MDI child is processed. If an application tries to modify

the system menu of an MDI child during the processing of the child's

WM_CREATE message, the system menu will not be changed.

MORE INFORMATION

================

It is common to try to alter a window's system menu during the processing

of its WM_CREATE message. This method has no effect on the system menu of

an MDI child, however, because of the way a MDI child window is created:

1. The MDI client window calls the CreateWindowEx() function to create

   the window.

2. Then, the MDI client window replaces the default system menu with

   the special MDI child system menu.

The WM_CREATE message is sent to the child window by CreateWindowEx().

Changes to the MDI child's system menu on WM_CREATE have no effect

because the MDI client assigns a special MDI system menu to the child

after CreateWindowEx() returns.

To work around this design decision, the child window procedure can

post a custom message to itself during the processing of its WM_CREATE

message. This custom message is processed after the MDI client has

finished creating the MDI child. The code for this workaround might

resemble the following:

#define WM_ADDMENUITEM (WM_USER+1)

LONG FAR PASCAL MDIChildWndProc(HWND hWnd,

                                WORD wMsg,

                                WORD wParam,

                                LONG lParam)

{

    switch (wMsg)

       {

    case WM_CREATE:

       PostMessage(hWnd, WM_ADDMENUITEM, 0, 0L);

       break;

    case WM_ADDMENUITEM:

       {

       HMENU        hMenu;

       hMenu = GetSystemMenu(hWnd, FALSE);

       InsertMenu(hMenu, -1, MF_BYPOSITION, IDM_NEW,

             (LPSTR)"New Item\0");

       DrawMenuBar(hWnd);

       }

       break;

    default:

       return DefMDIChildProc(hWnd, wMsg, wParam, lParam);

       }

    return 0;

}

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMdi


Introduction to Nonpreemptive Multitasking in Windows

Article ID: Q78155

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Applications in the Windows environment are scheduled using a

nonpreemptive multitasking system. Usually, multitasking operating

systems schedule tasks for execution based on some combination of time

slice and/or task priority. However, Windows does not preemptively

switch the processor away from a currently running application under

normal circumstances (excluding interrupts). Instead, multitasking in

Windows is based on the messaging system.

Windows-based applications must cooperatively offer to yield the processor

on a regular basis to allow Windows to multitask. Normally, an application

offers to yield by calling one of three functions: GetMessage(),

PeekMessage(), or WaitMessage(). An application may also yield when it

calls DialogBox(), DialogBoxIndirect(), DialogBoxParam(),

DialogBoxIndirectParam(), MessageBox(), or TrackPopupMenu().

MORE INFORMATION

================

The GetMessage Loop

-------------------

In the Windows environment, most applications have a central GetMessage()

loop that allows the application to cooperate with the other applications

running in the system.

When an application (called "App A") calls GetMessage(), the GetMessage()

function will return if there are any messages in App A's message queue. If

there are no messages, Windows will give control to another application

that has messages in its queue. If there are no messages waiting for any

application in the system, Windows idles. App A's call to GetMessage() will

not return until there is a new message in App A's queue.

Using this method, the Windows-based application with control will retain

control as long as messages are waiting in its queue. There is a small

wrinkle to this rule: Windows considers WM_PAINT and WM_TIMER messages to

be low-priority messages. If App A calls GetMessage() and has only low-

priority messages in its queue, Windows will pass control to an application

with high-priority messages waiting.

It is important to note that an application can retain control of the CPU

indefinitely if it does not call GetMessage(), PeekMessage(), or

WaitMessage(). However, an application that fails to periodically make one

of these three calls is very impolite, because it is not allowing Windows

to multitask.

Background Processing

---------------------

In the Windows environment, an application can perform a lengthy processing

task and allow Windows to multitask by using either a PeekMessage() loop or

a Windows timer. In both cases, the general idea is the same: break the

large processing task into small pieces, processing one piece at a time and

offering to yield at regular short intervals.

An application can use a PeekMessage() loop to perform background

processing because, unlike GetMessage(), PeekMessage() does not wait for a

message to be placed in the application's message queue before returning.

If there are no messages waiting, PeekMessage() returns FALSE.

A typical PeekMessage() loop resembles the following:

   while (bDoingBackgroundWork)

   {

      if PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)

      {

         TranslateMessage(&msg); // a message is ready - process it

         DispatchMessage(&msg);

      }

      else

      {

         // PeekMessage returned FALSE, which means no messages ready.

         // Do a small piece of background work here.

      }

   }

The PM_REMOVE flag must be specified in the wRemoveMsg parameter;

otherwise, the application will never yield. PeekMessage() will not yield

as long as there are messages in the application's queue. If the

application does not remove and process the messages, PeekMessage() may

send the application into an infinite loop.

An application creates a Windows timer with the SetTimer() function. An

application can use a Windows timer to do background processing by setting

a timer and doing a small piece of the background job each time a WM_TIMER

message is received or the timer notification function is called. Even if

the application is receiving a steady stream of WM_TIMER messages, other

applications will still have an opportunity to run because Windows

considers WM_TIMER messages to be a low priority.

It may be necessary to consider two other facts about Windows timers: they

are not asynchronous, and the highest resolution that can be obtained is

about 55 milliseconds.

REFERENCE

=========

For more information on using Windows timers, see Chapter 5, "The

Timer," in Charles Petzold's book "Programming Windows 3.1" (Microsoft

Press).

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMsg


Overcoming the 64 Kilobyte Limit for List Box Data

Article ID: Q79055

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows version 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article discusses a technique to overcome the 64K size limit for

strings in a list box. It does not discuss many of the implementation

details of owner-draw list boxes. For more information about these

implementation details, please query on the following words:

   prod(winsdk) and odlist

Standard list box controls are limited to 64K of data. An application

can overcome this barrier by implementing an owner-draw list box and

managing the data. This can be accomplished by using the list box to

store an index to the data, rather than storing the text of each

string.

MORE INFORMATION

================

In a standard list box control, the data strings are stored in a

global memory block that is allocated and managed by Windows. As the

number of strings in the list box grows, Windows increases the size of

the memory block as necessary to accommodate the data. However, this

block is limited to 64K.

One method to overcome this barrier is to implement an owner-draw list

box. For each string visible in the list box, Windows sends a

WM_DRAWITEM message to the window procedure of the parent window of an

owner-draw list box. When an application processes a WM_DRAWITEM

message, it displays the string.

For discussion purposes, assume that the application has an index into

a database of information. Each index identifies a string to be

displayed in the list box. When the application creates the list box,

it is important that the LBS_HASSTRINGS style NOT be specified.

Although the list box displays strings, the data stored in the list

box is a numeric index to the strings, not the strings themselves. Add

the data to the list box using a loop with the following statements:

   SendMessage(hListbox, LB_ADDSTRING, 0, lMyLongIndex);

The value lMyLongIndex is a value of type LONG that identifies the

string.

When the parent window's window procedure receives a WM_DRAWITEM

message, run the following code:

   lMyLongIndex = (LONG)(((LPDRAWITEMSTRUCT)lParam)->itemData);

   GetString(lMyLongIndex, szString);

   ...

   // Other WM_DRAWITEM processing

   ...

   DrawText(hDC, szString, ...);

This code retrieves the index of the selected item from the

DRAWITEMSTRUCT structure pointed to by lParam. GetString() is an

application-defined function that uses the index to retrieve the

string and place it into szString. Finally, the DrawText() function is

used to draw the string into the correct display context (identified

by hDC).

This method adds one level of indirection to each access of the list

box data. By storing an index to each string in the list box, rather

than storing the strings themselves, the amount of memory required to

maintain the strings in the list box is dramatically reduced. A list

box is limited to 64K of data. Storing a long value for each entry

allows up to 8160 entries in the list box. Each entry requires 8 bytes

(4 bytes for the long value and 4 bytes of overhead) and the list box

itself requires 256 bytes for overhead.

Additional reference words: 3.00

KBCategory: kbprg

KBSubcategory: UsrCtl


Subclassing the Desktop and Windows of Other Applications

Article ID: Q79276

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The code to subclass the desktop window, or windows that belong to

other applications, must be placed in a dynamic-link library (DLL).

MORE INFORMATION

================

In most cases, the desktop window uses the stack segment (SS) of the

currently scheduled task. This is done for performance reasons because

it reduces the number of task switches that take place when the

desktop receives paint or mouse messages. In some cases, the desktop

cannot be switched immediately to the currently scheduled task. In

this situation, it will temporarily use the SS of the previously

scheduled task.

When the desktop is subclassed, the data segment (DS) that the

subclass procedure uses is specified by the hInstance used in a

MakeProcInstance() call. However, the subclass procedure's SS depends

on the currently scheduled task, as described earlier. Because the

currently scheduled task may not be the task that subclassed the

desktop, it is possible that SS != DS when the subclass procedure is

executed. Therefore, the subclass procedure cannot assume that SS ==

DS. For this reason, the code to subclass the desktop must reside in a

DLL where it is assumed that SS != DS.

When a window belonging to another application is subclassed, the DS

that the subclass procedure uses is specified by the hInstance used in

the MakeProcInstance() call. The SS used by the subclass procedure is

the SS of the application that owns the window. Therefore, the

subclass procedure cannot assume that SS == DS. For this reason, the

code to subclass another application's window must reside in a DLL

where it is assumed that SS != DS.

The DLL in which the subclass procedure is placed should be compiled

with the Microsoft C Compiler's -Aw option, which tells the compiler

that SS != DS. Using this option causes the compiler to generate a

warning message when it detects the improper creation of a near

pointer to an automatic variable.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Windows Paintbrush File Format

Article ID: Q79342

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article provides the format of Windows Paintbrush files.

MORE INFORMATION

================

Paintbrush files are preceded by 32 bytes of header information.

Following the header is an index table into run-length encoded data.

Header

------

The header structure is defined in the C programming language, as

follows:

typedef struct

{

  WORD  key1;

  WORD  key2;

  WORD  dxFile;

  WORD  dyFile;

  /* NOTE: PBRUSH.EXE version 3.0 and 3.1 ignore the remaining values */

  /* in this structure. Future versions may or may not.               */

  WORD  ScrAspectX;

  WORD  ScrAspectY;

  WORD  PrnAspectX;

  WORD  PrnAspectY;

  WORD  dxPrinter;

  WORD  dyPrinter;

  WORD  AspCorX;

  WORD  AspCorY;

  WORD  wCheck;

  WORD  res1;

  WORD  res2;

  WORD  res3;

  WORD  res4;

} FILEHDR;

The first 32 bytes contain the header information described by the

above structure:

Bytes   Name     Win 1.0   Win 2.0           Win 3.0

-----   ----     -------   -------           -------

0 - 1   Key1     0x6144    0x694C      |0x6144| or |0x694C|

2 - 3   Key2     0x4D6E    0x536E      |0x4D6E|    |0x536E|

4 - 5   dxFile      X-dimension size of bitmap, in pixels

6 - 7   dyFile      Y-dimension size of bitmap, in pixels

8 - 9   SrcAspectX  Aspect ratio of the screen for which file was

                    created. Obtained from GetDeviceCaps(hScreenDC,

                    ASPECTX);

10 - 11 SrcAspectY  Aspect ratio of the screen for which file was

                    created. Obtained from GetDeviceCaps(hScreenDC,

                    ASPECTY);

12 - 13 PrnAspectX  Aspect ratio of the printer for which file was

                    created. Obtained from GetDeviceCaps(hPrinterDC,

                    ASPECTX);

14 - 15 PrnAspectY  Aspect ratio of the printer for which file was

                    created. Obtained from GetDeviceCaps(hPrinterDC,

                    ASPECTY);

16 - 17 dxPrinter   Resolution of the printer for which file was

                    created. Contains the number of pixels in the x

                    direction on the printer. The selected paper and

                    printer orientation affect this value.

18 - 19 dyPrinter   Resolution of the printer for which file was

                    created. Contains the number of pixels in the y

                    direction on the printer. The selected paper and

                    printer orientation affect this value.

20 - 21 AspCorX     Not used. Set to zero.

22 - 23 AspCorY     Not used. Set to zero.

24 - 25 wCheck      Checksum field. Makes sure that this file is Paint

                    format.

26 - 31 Reserved

Index

-----

The Paintbrush bitmap is run-length encoded. Each scan line is encoded

separately. The length of the resulting encoded string depends on the

pattern of the bitmap. There is an index table following the header.

Each entry of this index corresponds to a scan line. It is an unsigned

integer and shows the length of the encoded data. Following this table

is the encoded data.

   32 - xxx     xxx = 32 + sizeof(unsigned int) * dyPrinter

ALGORITHM FOR ENCODING

----------------------

Paint encoding is read in BYTES. There are two types of encoded data:

one starts with 0 (zero), the other starts with a nonzero value.

If the data starts with 0, it is a repeated byte pattern. The byte

following the 0 tells how many times to repeat the pattern and the

subsequent byte is the pattern itself. For example, 0, 0x80, 0xff,

should be expanded to eighty (hex) bytes of 0xff.

If the data starts with a nonzero value, X, the following X number of

bytes contain unmodified bitmap data, without recognizable pattern.

Each scan line can be composed of several of the above mentioned

groups of data. Of course, the groups should alternate, meaning that a

scan line can start with a repeated pattern followed by some random

pattern, which is followed by another repeated pattern.

To reach the data for the nth scan line, add up the values in the

index table from entry 0 to entry n - 1.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrFmt


PRB: BS_GROUPBOX-Style Child Window Background Painting Wrong

Article ID: Q79982

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When a BS_GROUPBOX style window is created, its background does not

erase correctly.

CAUSE

=====

The parent window of the BS_GROUPBOX style window has the

WS_CLIPCHILDREN style, which prevents the parent window from

erasing the group box's background.

RESOLUTION

==========

Subclass the group box window to process the WM_ERASEBKGND message

by erasing its background. Listed below is a code fragment to

demonstrate this procedure.

MORE INFORMATION

================

The WS_CLIPCHILDREN style causes a window to exclude the areas

occupied by child windows when the window paints its client area.

However, a BS_GROUPBOX style window is a static control that never

erases its background. Erasing the background removes any controls or

buttons that appear within the group box.

Therefore, when another child window is dropped over a group box and

subsequently dragged away, portions of that child window remain

visible in the group box's background. This problem does not occur

when the parent window does not have the WS_CLIPCHILDREN style.

The following code fragment should be placed in the group box's

subclass procedure. This code erases the background of the group box.

   case WM_ERASEBKGND:

       {

       HBRUSH  hBrush, hOldBrush;

       HPEN    hPen, hOldPen;

       RECT    rect;

       HDC     hDC;

       hDC = GetDC(hWnd);

       // Obtain a handle to the parent window's background brush.

       hBrush = GetClassWord(ghWnd, GCW_HBRBACKGROUND);

       hOldBrush = SelectObject(hDC, hBrush);

       // Create a background-colored pen to draw the rectangle

       // borders, where gWindowColor is some globally defined

       // COLORREF variable used to paint the window's background

       hPen = CreatePen(PS_SOLID, 1, gWindowColor);

       hOldPen = SelectObject(hDC, hPen);

       // Erase the group box's background.

       GetClientRect(hWnd, &rect);

       Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);

       // Restore the original objects before releasing the DC.

       SelectObject(hDC, hOldPen);

       SelectObject(hDC, hOldBrush);

       // Delete the created object.

       DeleteObject(hPen);

       ReleaseDC(hWnd, hDC);

       // Instruct Windows to paint the group box text and frame.

       InvalidateRect(hWnd, NULL, FALSE);

       // Insert code here to instruct the contents of the group box

       // to repaint as well.

       return TRUE; // Background has been erased.

       }

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrDlgs


Save System Resources with One Control per Control Class

Article ID: Q80084

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

When an application is designed to gather a large amount of

information from the user, the application can quickly consume many

system resources due to the number of controls that it creates. Rather

than creating many of the same type of control, an application can

create one control and move it around.

The ONEEDIT sample in the Software/Data Library demonstrates this

technique.

Download ONEEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ONEEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ONEEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ONEEDIT.EXE

For more information on what system resources are and how they are

consumed, query this Knowledge Base on the following words:

   system and resources and heap and user and gdi

MORE INFORMATION

================

ONEEDIT demonstrates collecting data for multiple fields with a single

edit control. It collects the following data by moving one control:

   Name (First, Middle, Last)

   Sex

   Social Security Number

   Birthday (Month, Day, Year)

   Address

   City

   State

   Zip Code

   Phone

The results of using this technique are transparent to the user;

however, an application designed in this way consumes far fewer system

resources because one edit control is used rather than many edit

controls. Fifteen fewer controls are required by ONEEDIT because it

uses this technique. This savings becomes more significant as the

number of controls within an application increases.

The ONEEDIT source includes an application programmer's interface

(API) that can be added to an application. For more information on the

API, see the file API.TXT included in the ONEEDIT archive file.

The remainder of this article lists some of the other techniques

implemented in ONEEDIT.

1. Mouse support

   - The application performs hit-testing to move the edit control

     directly to any valid field.

2. Supports both TAB and SHIFT+TAB keys to move from one field to another

   - TAB: forward

   - SHIFT+TAB: backward

3. Input validation

   - If the value input for the State field does not correspond to a

     valid two-letter state abbreviation (as defined by the U. S.

     Postal Service), a Help dialog box is displayed listing the valid

     abbreviations.

   - Only a number (or a minus sign) is valid input in some fields

     (Social Security Number, Birthday, Zip Code, and Phone fields).

   - The value for the Sex field must be m, M, f, or F.

4. Special case processing to move between fields of the Phone number

   - Automatically advances to next phone field when one field is

     filled.

   - BACKSPACE moves to the preceding phone field (for example, from

     the beginning of the prefix to the end of the area code).

   - Arrow keys allow movement between fields.

5. Context-sensitive help in State field

   - The States Help can be invoked directly by pressing F2 when the

     cursor is in the State field.

6. Icon automatically changes

   - The icon displayed in ONEEDIT client area changes depending on

     the contents of the Sex field.

Additional reference words: limit control window user heap 3.00 3.10

softlib ONEEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrRsc


Terminating the Creation of an MDI Child Window

Article ID: Q80125

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In an application designed with the Microsoft Windows multiple document

interface (MDI), there are situations in which it is desirable to destroy

an MDI child window during the processing of its WM_CREATE message. For

example, the design of the application may require terminating window

creation if a memory allocation needed to hold data for an MDI child fails.

Unfortunately, returning -1 to end processing of the WM_CREATE message will

not cleanly destroy the child window. Similarly, posting a WM_CLOSE message

will cause the display to flash as the child is drawn, made active, and

destroyed. This article describes a technique to avoid this unacceptable

visual effect.

To avoid the flash, the application can clear the redraw flag for the MDI

client window. This prevents the MDI client window and its children from

painting. The remainder of this article contains code to implement this

technique.

Before the application processes the MDI child window's WM_CREATE message,

it does not change its display to reflect the new child window. If the

application determines that it must abort creating the MDI child window at

this time, it should clear the MDI client window's redraw flag and post a

WM_CLOSE message to the child window. When the application processes the

WM_DESTROY message, turn the redraw flag back on. The following code

demonstrates these steps:

    case WM_CREATE:

        ...

        if (DestroyMePolitely)

            {

            SendMessage(hWndMDIClient, WM_SETREDRAW, FALSE, 0L);

            PostMessage(hWnd, WM_CLOSE, 0, 0L);

            }

        break;

    ...

    case WM_DESTROY:

        SendMessage(hWndMDIClient, WM_SETREDRAW, TRUE, 0L);

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMdi


Possible Causes of Dialog Box Creation Failure

Article ID: Q80843

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The dialog box creation routines (CreateDialog(), CreateDialogParam(),

CreateDialogIndirect(), CreateDialogIndirectParam(), DialogBox(),

DialogBoxParam(), DialogBoxIndirect(), and DialogBoxIndirectParam()) can

fail for several reasons. When one of these functions fails, the

dialog box is not displayed on the screen. Of the causes for dialog

box creation failure, this article discusses nine, which are listed

below, and provides a resolution or explanation:

1. Application runs out of file handles.

2. One or more text strings in a dialog resource starts with the

   character represented by the value 255 (0xFF).

3. Several small compiled resource (RES) files are combined using the

   MS-DOS command "COPY /b".

4. A dialog box with an edit control cannot be created when at least

   ten dialog boxes, each with one or more edit controls, are open

   simultaneously.

   NOTE: The above statement is not correct for Windows 3.1 because this is

   a problem relating to real mode and Windows 3.1 does not run in real

   mode.

5. The dialog resource is not included in the RC file.

6. Insufficient system resources.

7. In a dialog registered with a private dialog class, the dialog

   procedure does not return the value returned from DefDlgProc as its

   return value.

8. Wrong HINSTANCE value used.

9. A dialog box with an edit control or a combo box with an edit

   control must have a HEAPSIZE statement with a value > 0 in the

   .DEF file.

MORE INFORMATION

================

The order in which the causes are listed below does not provide any

indication of how often each cause occurs.

Cause 1

-------

Application runs out of file handles.

Resolution 1

------------

Use the SetHandleCount() function to open more file handles. For more

information on this procedure, query this Knowledge Base on the words:

   resources and SetHandleCount

Explanation 1

-------------

Windows requires a file handle to load a resource. Because each dialog box

creation routine loads dialog resources, an application must have at least

one file handle available for that purpose.

Cause 2

-------

One or more text strings in a dialog resource start with the character

represented by the value 255 (0xFF).

Resolution 2

------------

For an explanation of two methods to work around this cause, query this

Knowledge base on the words:

   string and resource and 255

Explanation 2

-------------

Windows uses the number 255 to indicate that a resource is represented by

an ordinal value instead of by a string name. During the process of parsing

the resource that contains one of these characters, Windows incorrectly

skips the next two bytes and treats the new position in the resource as the

next piece of data.

Cause 3

-------

Several small compiled resource (RES) files are combined using the MS-DOS

command "COPY /b".

Resolution 3

------------

Use the #include directive to combine the files at the source level. If the

Windows Resource Compiler cannot handle the large RC file, consider storing

the resources in a resource-only DLL. For more information, query this

knowledge base on the words:

   combined and res

Explanation 3

-------------

The Resource Compiler shipped with version 3.0 of the Windows Software

Development Kit (SDK) has been enhanced to handle resource files much

larger than its Windows 2.x counterpart. The format of the compiled

resource files in Windows 3.0 does not support concatenation of RES files.

Cause 4

-------

A dialog box with an edit control cannot be created when at least ten

dialog boxes, each with one or more edit controls, are open simultaneously.

Resolution 4

------------

Specify the DS_LOCALEDIT style in the dialog box template, or create the

edit control explicitly with the CreateWindow() function.

Explanation 4

-------------

For more information, query this Knowledge Base on the words:

   dialog and GlobalAlloc and fails

Cause 5

-------

The dialog resource is not included in the RC file.

Resolution 5

------------

Use RCINCLUDE to include the dialog resource in the RC file.

Explanation 5

-------------

Include the DLG file created by the Dialog Editor into

the RC file so the Resource Compiler can add the dialog resource to

the executable file.

Cause 6

-------

Insufficient system resources.

Resolution 6

------------

Verify that system resources are not lost because an application does not

delete objects that it creates. For more information, query this Knowledge

Base on the words:

   lost and heapwalk

The article "Careful Windows Resource Allocation and Cleanup Improves

Application Hygiene," in the September 1991 issue of the "Microsoft

Systems Journal" discusses this issue further.

Explanation 6

-------------

Unless each application frees all the resources that it allocates,

eventually Windows does not have enough memory to create the controls

and/or the dialog box itself.

Cause 7

-------

In a dialog registered with a private dialog class, the dialog procedure

does not return the value returned from DefDlgProc() as its return value.

Resolution 7

------------

Whenever the private-class dialog procedure passes an unprocessed message

to DefDlgProc(), the dialog procedure must propagate the value returned by

DefDlgProc().

Explanation 7

-------------

When a private-class dialog procedure passes an unprocessed message to

DefDlgProc(), it must return the value returned from DefDlgProc(). This

behavior differs from that of a default-class dialog procedure, which

usually returns FALSE outside the message switch when it does not process a

message. If a private-class dialog procedure is implemented in this way,

and the procedure does not process the WM_NCCREATE message, it will return

FALSE. The CreateWindow() function sends the WM_NCCREATE message to create

the non- client area of the dialog window. CreateWindow() treats a response

of FALSE from the dialog procedure as failure and returns a NULL handle to

the application.

Cause 8

-------

Wrong HINSTANCE value used.

Resolution 8

------------

Specify the application's instance handle.

Explanation 8

-------------

The dialog box creation routine must specify the application's instance

because the dialog template is stored in the application instance.

Cause 9

-------

A dialog box with an edit control or a combo box with an edit control must

have a HEAPSIZE statement with a value > 0 in the .DEF file.

Resolution 9

------------

Set the value of HEAPSIZE to > 0 in your .DEF file.

Explanation 9

-------------

Windows allocates memory for edit controls out of your local heap. If you

do not have a HEAPSIZE statement, it cannot create the edit control.

Additional reference words: fails modal modeless 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Microsoft Drag-Drop Server Strategy

Article ID: Q81047

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

Windows version 3.1 supports a drag-drop protocol that enables an

application to be the client of File Manager. When an application

implements the drag-drop feature, a user can select one or more files

in File Manager, drag them to a client application, and drop them. At

this point, the client application receives a message and it can

determine which files were dropped and the exact location at which the

files were dropped.

At present, version 3.1 of the File Manager is the only server

application that supports the drag-drop protocol. Although no Windows

function is available to enable an application to become a drag-drop

server, Microsoft intends to provide this functionality in a future

release of Windows.

The drag-drop interface mechanism will change to provide additional

functionality that can be used by a future server application to

support application cooperation and shell integration. The new

mechanism will continue to support the Windows 3.1 drag-drop client

protocol.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDnd


WH_CALLWNDPROC, WH_GETMESSAGE Hooks Sample Code

Article ID: Q81332

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

HOOKALL2 is a file in the Microsoft Software Library that demonstrates

using the WH_GETMESSAGE and WH_CALLWNDPROC hooks in Windows 3.1.

HOOKALL2 contains the code for a dynamic-link library (DLL) with

functions that set and remove the hooks, as well as the hook filter

functions. The DLL uses the new hook functions provided by Windows

3.1: SetWindowsHookEx, UnhookWindowsHookEx, and CallNextHookEx.

HOOKALL2 also contains code for a TESTHOOK application that tests the

DLL.

HOOKALL2 updates the HOOKALL sample to use the features provided by

Windows 3.1. For more information about HOOKALL, query on the

following words in the Microsoft Knowledge Base:

   hookall

Download HOOKALL2.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HOOKALL2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HOOKALL2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HOOKALL2.EXE

With the exception of WM_LBUTTONDOWN messages, the hook filter

functions pass all messages directly to the next hook function in the

hook chain. When they receive a WM_LBUTTONDOWN message, the filter

functions draw a rectangle of random size and color in the TESTHOOK

application's client area. One corner of the rectangle is at the point

where the user pressed the mouse button.

Additional reference words: 3.10 softlib HOOKALL2.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrHks


DDEML CONVINFO Structure, wConvst Field Description

Article ID: Q81547

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

The documentation for the Dynamic Data Exchange Management Library

(DDEML) lists the possible values for the wConvst field, but it does

not explain the causes for these values. The following table lists the

possible values for the wConvst field and the causes of each:

wConvst             Cause

------------------------------------------------------------------------

XST_ADVACKRCVD      The advise transaction was just completed.

XST_ADVDATAACKRCVD  The advise data transaction was just completed.

XST_ADVDATASENT     Advise data has been sent and is awaiting an

                    acknowledgement.

XST_ADVSENT         An advise transaction is awaiting an

                    acknowledgement.

XST_CONNECTED       The conversation has no active transactions.

XST_DATARCVD        The requested data has just been received.

XST_EXECACKRCVD     An execute transaction just completed.

XST_EXECSENT        An execute transaction is awaiting an

                    acknowledgement.

XST_INCOMPLETE      The last transaction failed.

XST_INIT1           Mid-initiate state 1.

XST_INIT2           Mid-initiate state 2.

XST_NULL            Preinitiate state.

XST_POKEACKRCVD     A poke transaction was just completed.

XST_POKESENT        A poke transaction is awaiting an

                    acknowledgement.

XST_REQSENT         A request transaction is awaiting an

                    acknowledgement.

XST_UNADVACKRCVD    An unadvise transaction just completed.

XST_UNADVSENT       An unadvise transaction is awaiting an

                    acknowledgement.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


Timers and Timing in Microsoft Windows

Article ID: Q81592

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following is the text of the article "Timers and Timing in Microsoft

Windows". This article is available in Windows Help file format in the

Microsoft Software Library in addition to the text presented below.

Download TIMER2.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TIMER2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735

      Download TIMER2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TIMER2.EXE

            Timers and Timing in Microsoft(R) Windows(TM)

                           by Bob Gunderson

ABSTRACT

--------

This article covers the following aspects of timers and timing in the

Microsoft(R) Windows(TM) graphical environment:

 - How Windows-based applications set up and use timers to perform an

   operation periodically

 - Limitations of timers

 - Creating and destroying timers using the SetTimer and KillTimer

   functions

 - How timer events are detected, recorded, and dispatched internal to

   Windows

 - How standard and enhanced modes affect timers and timing

 - How TOOLHELP.DLL can be useful to timers

 - A description of the INT 2Fh interface to the virtual timer driver

   (VTD.386)

TIMERS AND THEIR USES

---------------------

Microsoft Windows timers create an event that periodically triggers a

specific action in an application. The event can be a WM_TIMER message

returned from a GetMessage or a PeekMessage function, or it can be a

call to a specified function.

Timers are used in many ways. For example, the Windows Clock

application uses a timer to awaken the application periodically to

update the clock face. Internally, carets flash on timer events. Also,

the rate at which list boxes and edit controls scroll is based on

timer events. Without timers, the application would remain active in

delay loops, violating the "give up control when you are not active"

rule needed to keep the nonpreemptive tasking model of Windows

running.

Instead, a Windows-based application creates a timer with an appropriate

delay and then suspends itself in a standard GetMessage loop. When the

timer delay expires, the timer event is generated, and the application

can perform the necessary operation. At this point the timer can

either be destroyed or be left active. If it is left active, another

timer event is generated when the timer delay again expires. This

cycle continues until the timer is destroyed. Windows version 3.0 can

maintain only 16 active timers; Windows version 3.1 can maintain only

32 active timers. Therefore, an application that is not actively using

a timer should destroy it so the timer can be used by another

application.

Tip: Timers are a limited resource. If all timers are in use, the

SetTimer function fails. Unless keeping a timer active is absolutely

essential to a program, the application must destroy the timer when it

is not in use.

Creating and Destroying a Timer

-------------------------------

A timer is created when a program calls the SetTimer function. A timer

can dispatch a message to a particular window or call a specified

callback function. The lpTimerFunc parameter to SetTimer determines

whether a message is sent or a callback function is called. When

GetMessage and PeekMessage determine that a timer event has occurred,

they return a WM_TIMER message. The lParam of this message contains

the lpTimerFunc value passed to SetTimer. The code in DispatchMessage

examines the lParam of the WM_TIMER message and dispatches the message

to the appropriate window procedure if the lParam is NULL, or calls

the callback if the lParam is not NULL. If the lpTimerFunc parameter

contains a non-null value, it is assumed to be the FARPROC address of

an exported callback function (use MakeProcInstance on it too). This

parameter must be correct because Windows does not validate it.

Windows simply makes a far call to the specified address. The format

of the callback is described in the Microsoft Windows Software

Development Kit (SDK) documentation for the SetTimer function, but the

following table better describes the parameters to the callback.

   Parameter Description

   --------- -----------

   hWnd      The window handle that was passed as the hWnd parameter to

             the SetTimer function. Because Windows never looks at this

             parameter, you can pass a NULL here if the callback doesn't

             need an hWnd or if no hWnd is available at the time SetTimer

             is called.

   wMsg      Always WM_TIMER.

   nIDEvent  The timer's ID.

   dwTimer   DispatchMessage calls the GetTickCount function and then

             passes the value obtained in dwTimer.

If the lpTimerFunc parameter to SetTimer is NULL, the timer generates

a WM_TIMER message for the window specified by the hWnd parameter. The

lParam of the WM_TIMER message returned from GetMessage or PeekMessage

is NULL, which causes DispatchMessage to send the message to the

appropriate Windows procedure. If hWnd is not a valid window handle,

DispatchMessage returns an "Invalid Window Handle" FatalExit (code

0x0007). When the window procedure gets the WM_TIMER message, the

wParam contains the timer's ID, and the lParam is NULL.

When a timer is created, it is assigned an ID. Timer IDs are passed to

timer callback functions and with WM_TIMER messages. Timer IDs are

also used when killing the timer with the KillTimer function. The

nIDEvent parameter lets an application choose the timer's ID if the

hWnd parameter is not NULL. If the hWnd parameter is NULL, Windows

chooses an ID and returns it from the SetTimer function. In this case,

the nIDEvent parameter is ignored, regardless of the value of

lpTimerFunc.

The return value from SetTimer is 0 (zero) if the timer could not be

created. This situation occurs only when all timers are in use before

the function is called. SetTimer returns a nonzero value if the timer

is successfully created. If the hWnd parameter is NULL, this nonzero

value is the timer's ID. If hWnd is nonzero, the function succeeded,

and the timer's ID is the value passed in nIDEvent. The timer's ID

must be saved because it will be needed later to kill the timer.

Tip: If the application calls SetTimer with a nonzero hWnd, it must

specify the timer ID. Contrary to the Windows version 3.0

documentation, this ID, not the SetTimer return value, must be used

when killing the timer.

If SetTimer is called with exactly the same hWnd and ID as an already

active timer, Windows resets the timer rate to the new value passed in

the wElapse parameter. This method is convenient for changing the rate

of a timer without having to kill it and create a new one. Note that

if hWnd is NULL, the ID value passed must be the timer's ID as

returned from the preceding SetTimer call.

In all flavors of SetTimer, the timer event rate is passed in the

wElapse parameter. It is specified in milliseconds but is not nearly

that precise.

A timer is killed by calling the KillTimer function. KillTimer

requires two parameters: the hWnd that was passed to SetTimer when the

timer was created and the timer's ID. Note again that if hWnd is

NULL, the timer's ID is the return value from the SetTimer call, not

the value passed in the nIDEvent parameter.

Timer Implementation and the Effect on Timer Resolution

-------------------------------------------------------

All ISA (IBM PC/AT and compatible) computer systems generate a

hardware interrupt on IRQ0 18.2 Hz. This interrupt is mapped to INT 8

and can be intercepted by any application that wants to hook it. At

18.2 Hz, the interrupt occurs approximately once every 55

milliseconds. The Windows system driver hooks INT 8 and maintains the

value returned by the GetTickCount function. Thus, this value is

accurate only to within 55 milliseconds.

Interrupt-level timer services via INT 8 are fairly straightforward

and easy to understand. Providing timer services to a Windows-based

application is much more difficult. The two major complications are

the inability to call Windows-based applications at interrupt level and the

nonpreemptive nature of the Windows tasking model. A timer event for a

Windows-based application must behave the same as other interrupt-driven

events such as mouse and keyboard events: The event must be detected

and recorded at interrupt level but dispatched only to the appropriate

application the next time the application asks for messages.

Therefore, the delay between the interrupt event occurring and the

application receiving it is nondeterministic.

Although the hardware timer rate is 18.2 Hz, the rate at which

Windows-based applications receive timer messages is quite a bit slower and

is affected by other applications that are running.

Windows hooks INT 8 at initialization time. As a timer is created, a

timer data structure is reserved for the timer. This data structure

contains information about the timer, such as which hWnd to send the

message to or which FARPROC to call, the timer ID, or the delay time

between events. This delay time is then copied into a current delay

counter. When the INT 8 handler is called, the current delay counter

for each active timer is decremented by 55 (because the delay time is

specified in milliseconds). If in doing so the current delay counter

reaches 0, a flag is set to indicate that an event should be generated

for this timer.

GetMessage and PeekMessage first check to see if any posted messages

or any keyboard or mouse events are waiting for the application. If

none are, GetMessage and PeekMessage check to see if any timers

created by the active application have triggered. If one of these

timers has triggered, GetMessage and PeekMessage create a WM_TIMER

message with the appropriate wParam and lParam and return the message.

Contrary to the SDK documentation, the message is never placed in the

applications queue. DispatchMessage properly dispatches the message

either to the appropriate window or to the specified callback

function.

When a timer is created, it is associated with the currently active

task. When GetMessage and PeekMessage scan for timer events, they look

only at timers associated with the currently active task. Although not

normally a problem, this activity does prevent an application from

creating a timer that would dispatch WM_TIMER messages to a window in

another task. Also, timers should not be created in systemwide hooks

such as the keyboard hook because the hook is likely to be called

while another task is active.

Tip: Be careful with SetTimer calls inside dynamic-link libraries

(DLLs). If a DLL creates a timer on behalf of a task and then the task

terminates, the timer is destroyed.

ENHANCED-MODE VIRTUALIZATION

----------------------------

When running in enhanced mode, Windows takes advantage of the virtual

machine (VM) capabilities of the Intel386(TM) hardware. All MS-DOS-based

applications run as if each had the entire system to itself. All

Windows-based applications run together in a single VM. All VMs, if none

are paged, reside simultaneously in physical memory, but only one at a

time is active. To arbitrate among the VMs, Windows loads a

virtualization layer when running in enhanced mode. This layer acts as

a traffic cop, directing hardware events to the appropriate VM on the

basis of which VM is active.

One of the many hardware events that is virtualized is INT 8, the

timer. When a VM is not the active VM, it does not receive INT 8

events at the standard 18.2 Hz rate. The Windows VM not receiving INT

8 events at a standard rate plays havoc with the value returned by the

GetTickCount function as well as with any active timers set by Windows-

based applications. In this environment, WM_TIMER messages are at the mercy

of the enhanced-mode scheduler and the relative priority of the

Windows VM. Probably more problematic is the value returned from

GetTickCount. Because this value increments by 55 only when the

Windows VM sees an INT 8, it is not at all accurate in enhanced mode.

Applications that require accurate event timing must not use

GetTickCount to determine time delays. Instead, they must use the

clock maintained by MS-DOS (INT 21H, function 2CH), TOOLHELP.DLL

services, or the VTD (described below).

Tip: Windows timers operate erratically in enhanced mode when MS-DOS-based

applications are active.

Tip: The GetTickCount function cannot be used to time events

accurately because it is not regularly updated when the MS-DOS VMs are

active. GetTickCount is inaccurate both in standard mode and in

enhanced mode.

STANDARD-MODE TASK SWITCHING

----------------------------

Standard-mode task switching has essentially the same effect on the

GetTickCount value and Windows timers as does enhanced-mode

virtualization, but for a different reason. When a task is switched in

standard mode, either between an MS-DOS-based application and Windows or

between two MS-DOS-based applications, Windows swaps the entire running

application to disk and then loads the new application from its

previously saved swap file. While running an MS-DOS-based application, the

Windows INT 8 handler obviously is not being called because Windows is

not in memory. Thus, any active timers do not count down, and the

GetTickCount value does not increment. This problem is less obvious in

standard mode than in enhanced mode because MS-DOS-based applications

cannot run in a window in standard mode.

USING TOOLHELP.DLL

------------------

TOOLHELP.DLL is a new library being developed for Windows version 3.1,

but it will also run under Windows version 3.0. It was developed for

use by debuggers and profilers, but its ability to provide high-

resolution timing services is useful to other types of Windows-based

applications. The TimerCount function can return system time

information that is accurate to the millisecond. The function returns

two values: a count of how long Windows has been running and a

cumulative total of how long the Windows VM has been active. In

standard mode, both values are the same and contain the time Windows

has been running; however, the counts are accurate only if no task

switches take place, because they are not maintained while MS-DOS-based

applications are active.

VIRTUAL TIMER DEVICE

--------------------

The virtual timer device (VTD) provides timer services that are more

accurate than the value returned by GetTickCount. TOOLHELP.DLL

provides a convenient way to access the VTD services via the

TimerCount function. Under some conditions, however, calling

TimerCount is not possible or appropriate. Under these rare

conditions, an application can call the VTD directly. The VTD in

Windows version 3.1 is the first version of the VTD that supplies

these timer services.

The VTD uses the 8253 Programmable Interval Timer chip to obtain its

values. The 8253 countdown register is always set to FFFFh, and the

rate is set to 1.196 MHz. Thus, an interrupt is generated about 18.2

times per second, or roughly every 55 milliseconds. This is the

interrupt that comes through INT 8. The countdown register of the 8253

is accessible at any time, and the VTD uses it to obtain more accurate

time information than is available through INT 8.

The address of the function in the VTD that provides these timer

services is obtained in a slightly roundabout way. The application

must execute an INT 2Fh instruction with the AX register set to 1684h

and the BX register set to 5. This instruction returns the address of

the VTD timer services function in ES:DI.

The following values can be obtained from the VTD by calling this

function with the appropriate value in the AX register.

Version Number

--------------

The VTD version number is obtained by calling the VTD with AX set to

0. The major version number is returned in AH, and the minor version

number is returned in AL. The version number does not change to match

the version of Windows with which the VTD is shipped. Instead, the

version number changes when any modifications or additions are made to

the services provided. The version values returned from the VTD in

Windows version 3.1 are AH set to 3 and AL set to 0Ah.

Current Clock Tick Time

-----------------------

The VTD maintains a 64-bit value that is accurate to 0.8 microseconds.

This value is obtained by calling the VTD with AX set to 0100h. The

64-bit value is returned in EDX:EAX. The returned value indicates the

time Windows has been running based on a 1.196 MHz clock.

Current System Time in Milliseconds

-----------------------------------

The VTD also maintains the time in milliseconds Windows has been

running. This value can be obtained by calling the VTD with AX set to

0101h. The 32-bit result is returned in the EAX register. This value

is not affected by changes in VM activation.

Current VM Time in Milliseconds

-------------------------------

The cumulative time the current VM has been active can be obtained by

calling the VTD with AX set to 0102h. The 32-bit result is returned in

the EAX register. The value returned is the cumulative amount of time

that the VM that is active at the time of the call has been active.

All applications will incur an overhead when calling the VTD (also

when calling TOOLHELP.DLL because it, in turn, calls the VTD). Calling

the VTD causes a ring transition because the VTD runs in ring 0. Ring

transitions are about 100 times slower than a far call but still take

less than 1 millisecond. The overhead for a ring transition to the VTD

is constant.

Copyright 1992 by Microsoft Corporation.  All rights reserved.

Additional reference words: 3.00 3.10 softlib TIMER2.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrTim


WM_CTLCOLOR Processing for Combo Boxes of all Styles

Article ID: Q81707

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Windows sends a WM_CTLCOLOR message to the parent of a control window

to enable the parent to specify the color of the control. A

notification code, which is the value of the high-order word of the

lParam, accompanies the WM_CTLCOLOR message to indicate the control

type for a WM_CTLCOLOR message. Windows does not define a notification

code that enables an application to change the color of a combo box

control. However, Windows sends WM_CTLCOLOR messages to a combo box

control that relate to its component parts: one message for the list

box portion and, if applicable, another message for the edit control

portion. An application can subclass the control to intercept and

process these messages. This article discusses how to perform the

subclassing and how to address the problems that arise when an

application changes the colors of a combo box under Windows 3.0.

MORE INFORMATION

================

Under Windows versions 3.0 and later, Windows sends a WM_CTLCOLOR

message to a combo box for each of its individual elements. An

application can subclass the combo box control to process the message.

The text below discusses each of the combo box styles and how the

color can be changed for each style.

CBS_SIMPLE Style

----------------

Under Windows 3.0, an application must process three WM_CTLCOLOR

notifications codes, CTLCOLOR_EDIT, CTLCOLOR_MSGBOX, and

CTLCOLOR_LISTBOX, to change the colors for a CBS_SIMPLE-style list

box. Under Windows 3.1, the application is not required to process the

CTLCOLOR_MSGBOX notification.

Each time the application processes a notification, it must set the

foreground and background colors, using SetTextColor and SetBkColor,

respectively. The wParam accompanying the WM_CTLCOLOR message contains

a handle to the appropriate display context. In addition, the

application must return a valid handle to the appropriate background

brush that Windows will use to paint those areas not occupied by text.

CBS_DROPDOWN Style

------------------

To change the colors of a CBS_DROPDOWN-style combo box under Windows

3.0, process the same three notifications as for the CBS_SIMPLE combo

box. However, there is a difficulty with regard to setting the text

color. In the drop-down list box, the colors set with SetBkColor and

SetTextColor are not used. Instead, the combo box uses the system

default colors. As a workaround, change the combo box to the

owner-draw style. Process the WM_DRAWITEM message to draw the

individual items with the desired text colors.

For more information on using an owner-draw combo box in an

application, query on the following words in the Microsoft Knowledge

Base:

   prod(winsdk) and owncombo

Under Windows 3.1, it is not necessary to use an owner-draw combo box.

The application can process the CTLCOLOR_EDIT and CTLCOLOR_LISTBOX

notifications to change the color of a combo box.

CBS_DROPDOWNLIST Style

----------------------

To change the color of a CBS_DROPDOWNLIST-style combo box, process the

CTLCOLOR_LISTBOX notification. However, the application must process

this notification in the combo box subclass procedure and in the

window procedure for the parent window of the combo box.

Under Windows 3.0, the text color problem discussed above for

CBS_DROPDOWN-style combo boxes is evident for CBS_DROPDOWNLIST combo

boxes. To address this problem, the application must use an owner-draw

combo box.

Although it is not necessary to use an owner-draw combo box under

Windows 3.1, the application must process the CTLCOLOR_LISTBOX

notification in both the combo box subclass procedure and in the

window procedure for the parent window of the combo box.

NOTE: WM_CTLCOLOR with codes is obsolete in Win32. Each code now has its

own message, such as WM_CTRLCOLORBTN, WM_CTLCOLORLISTBOX, and so forth.

Otherwise, things work the way they do in Windows 3.1.

Additional reference words: 3.00 3.10 combobox listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Creating Applications that Task Manager Does Not Tile

Article ID: Q81708

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

A variety of applications that provide various types of information

have been developed for the Windows graphical environment. Depending

on the amount of information that the application presents, an

application icon may provide enough screen space to show the

information. The FREEMEM program in Chapter 5 of Charles Petzold's

book "Programming Windows 3" (Microsoft Press) demonstrates presenting

status data on an icon.

When an application has more data than can be readily represented on

an icon, the user will often size the application to provide just the

information necessary, and place the application's window in a

convenient place on the screen. However, in this situation, if the

user selects Cascade or Tile from the Task Manager window to arrange

the active applications, the status window will probably change size

and position on the screen.

This article presents a technique that an application can use to

prevent itself from being cascaded or tiled by the Task Manager.

MORE INFORMATION

================

To prevent an application from changing position when the Task Manager

rearranges windows, perform the following four steps:

1. Create a minimum window procedure, called DummyWndProc, with the

   following code:

   long FAR PASCAL DummyWndProc(HWND hwnd, WORD message,

                                WORD wParam, LONG lParam)

   {

      return DefWindowProc(hwnd, message, wParam, lParam);

   }

2. Register a minimum window class, DummyClass, that uses DummyWndProc

   as the class procedure. Specify the application's icon as the class

   icon.

3. Create an invisible pop-up window of class DummyClass. Specify the

   application's name for the window caption text. Optionally, the

   coordinates for this invisible window can specify a location off

   the screen.

4. In the CreateWindow call for the top-level visible window, specify

   the window from step 3 as the hwndParent parameter.

There is one caveat to using this method. If an application uses

PostMessage with the hwnd parameter set to -1 to post a message to all

applications, the invisible pop-up window will receive the message. If

the application depends on any globally posted message, it is

necessary to modify the DummyWndProc code above.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


Using the WM_GETDLGCODE Message

Article ID: Q83302

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Windows sends a WM_GETDLGCODE message to controls in a dialog box or

in a window where the IsDialogMessage function handles keyboard input.

Generally, an application processes the WM_GETDLGCODE message to

prevent Windows from performing default processing in response to

keyboard messages. The WM_KEYDOWN, WM_SYSCHAR, and WM_CHAR messages

are examples of keyboard messages.

This article discusses the various codes that make up the value

returned from the WM_GETDLGCODE message.

MORE INFORMATION

================

Windows sends a WM_GETDLGCODE message to a control for the following

three reasons:

 - To determine whether the control will process a particular type of

   input.

 - To determine whether the text contents of an edit control are

   selected when, as a result of the user pressing the TAB key,

   the edit control receives the input focus.

 - To determine the type of a button.

The following text documents the values of the wParam and lParam

parameters for the WM_GETDLGCODE message:

   Parameter    Description

   ---------    -----------

   wParam       Not used.

   lParam       If lParam is not NULL, it is a far pointer to an MSG

                structure that contains a message that is being sent to

                the control. Windows versions 3.0 and 3.1 use lParam only

                to send keyboard input to the control. Keyboard messages

                include WM_KEYDOWN, WM_SYSCHAR, and WM_CHAR. Future

                versions of Windows may use lParam to send other message

                types to controls.

The window procedure for each predefined control returns an

appropriate value in response to a WM_GETDLGCODE message. The value is

one or more of the following codes, combined with the Boolean OR

operator:

   Code                   Meaning

   ----                   -------

   DLGC_BUTTON            Control is a button (of any kind).

   DLGC_DEFPUSHBUTTON     Control is a default push button.

   DLGC_HASSETSEL         Windows will send an EM_SETSEL message to the

                          control to select its contents.

   DLGC_RADIOBUTTON       Control is an option (radio) button.

   DLGC_STATIC            Control is a static control.

   DLGC_UNDEFPUSHBUTTON   Control is a push button but not the default

                          push button.

   DLGC_WANTALLKEYS       Control processes all keyboard input.

   DLGC_WANTARROWS        Control processes arrow keys.

   DLGC_WANTCHARS         Control processes WM_CHAR messages.

   DLGC_WANTMESSAGE       Control processes the message in the MSG

                          structure that lParam points to.

   DLGC_WANTTAB           Control processes the TAB key.

The return codes above can be used by user-defined controls or, in a

subclass procedure, to modify the behavior of predefined controls. To

subclass a control, call the predefined control's window procedure

first, then modify the necessary bits in the return code.

DLGC_WANTALLKEYS, DLGC_WANTARROWS,

DLGC_WANTCHARS, DLGC_WANTMESSAGE, and DLGC_WANTTAB Return Codes

---------------------------------------------------------------

When a control processes the WM_GETDLGCODE message and the value it

returns has one of the DLGC_WANT* bits set, the control will process

the specified message type and Windows will not do any default

processing for messages of the specified type.

For example, the code returned by a list box includes DLGC_WANTARROWS

to indicate that the list box processes arrow keys. When a list box

has the focus and the user presses a DOWN ARROW key, Windows sends a

WM_GETDLGCODE message to the list box. Because the return value

includes the DLGC_WANTARROWS code, Windows allows the list box to

process the arrow keystroke and performs no further processing. If the

return value did not include the DLGC_WANTARROWS code, Windows would

continue processing the arrow keystroke and would change the focus to

the next control in the current control group.

As another example, the value returned by an edit control includes the

DLGC_WANTCHARS code while the value returned by a button does not.

Consequently, if a button has the focus, and the user types a valid

mnemonic character, Windows sets the focus to the control in the

dialog box that corresponds to the mnemonic. (If a control has a

mnemonic character, it is underlined in the control's label.) If an

edit control has the focus and the user types a mnemonic character,

however, Windows does not change the input focus because the edit

control processes the resulting WM_CHAR message and Windows does not

perform its default processing for a mnemonic character.

DLGC_WANTMESSAGE Code

---------------------

A control returns a value that includes the DLGC_WANTMESSAGE code

after it processes the message sent through the lParam that

accompanies the WM_GETDLGCODE message. The DLGC_WANTMESSAGE code

indicates that the application does not want default processing for

the message to continue. The messages sent to the control include

WM_KEYDOWN, WM_SYSCHAR, and WM_CHAR. Future versions of Windows could

send other messages to controls using this mechanism.

The following code provides an example of processing the WM_GETDLGCODE

message in a control's subclass procedure. In the example, the user

presses the "X" key to select a check box and presses the "O" key to

clear the check box:

   case WM_GETDLGCODE:

      // Call the check box window procedure first

      lRet = CallWindowProc(lpCheckProc, hWnd, wMessage, wParam,

                            lParam);

      // If lParam points to an MSG structure

      if (lParam)

      {

         lpmsg = (LPMSG)lParam;

         if (lpmsg->message == WM_CHAR)

         {

            if (lpmsg->wParam == 'x' || lpmsg->wParam == 'X')

            {

               // Select the check box when user presses "X"

               SendMessage(hWnd, BM_SETCHECK, TRUE, 0);

               lRet |= DLGC_WANTMESSAGE;

            }

            else if (lpmsg->wParam == 'o' || lpmsg->wParam == 'O')

            {

               // Clear the check box when user presses "O"

               SendMessage(hWnd, BM_SETCHECK, FALSE, 0);

               lRet |= DLGC_WANTMESSAGE;

            }

         }

      }

      return lRet;

When a check box control's subclass procedure includes the code above,

Windows performs no further processing for WM_CHAR messages for the X,

x, O, and o characters because the value returned from WM_GETDLGCODE

includes the DLGC_WANTMESSAGE code. In the example above, the control

could have returned DLGC_WANTCHARS instead of DLGC_WANTMESSAGE because

the WM_CHAR message is the only message processed by the control.

DLGC_HASSETSEL Code

-------------------

An edit control returns a value that includes the DLGC_HASSETSEL code

to indicate that Windows should select all the text in an edit control

when the control receives the input focus through the tabbing

sequence.

For example, when a control in a dialog box receives the focus because

the user pressed the TAB key, Windows sends a WM_GETDLGCODE message to

the control. If the value returned from the edit control includes the

DLGC_HASSETSEL code, the edit control indicates that all text in the

edit control should be selected. Consequently, Windows sends an

EM_SETSEL message to the control to select all its contents.

An application can alter this behavior and prevent the contents from

being selected when the control receives the focus through tabbing, by

subclassing the edit control and removing the DLGC_HASSETSEL code from

its return value. Note that the subclassing code below does not change

any other bits in the return value.

   // In the subclass procedure

   case WM_GETDLGCODE:

      // Call the original edit control window procedure

      lRet = CallWindowProc(lpEditProc, hWnd, wMessage, wParam,

                            lParam);

      // Clear the DLGC_HASSETSEL bit from the return value

      lRet &= ~DLGC_HASSETSEL;

      return lRet;

DLGC_BUTTON, DLGC_DEFPUSHBUTTON,

DLGC_UNDEFPUSHBUTTON, DLGC_RADIOBUTTON, DLGC_STATIC Codes

---------------------------------------------------------

These codes are used to determine a control's attributes.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Extended Characters Different Under Windows

Article ID: Q83461

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

Applications in the Windows environment must typically deal with two

different character sets: the ANSI (American National Standards

Institute) character set and the OEM (original equipment manufacturer)

character set. Conversely, applications in the MS-DOS environment must

deal only with the OEM character set. This article describes how

Windows deals with the ANSI and OEM character sets.

1. When ALT+xxx is used to enter a character from the OEM character

   set into an application in the Windows environment that uses the

   ANSI character set, Windows displays the character in the ANSI

   character set that most closely matches the entered character.

2. When a character from the OEM character set is entered into a file

   using a text editor under MS-DOS and the file is displayed under

   Windows, the character from the ANSI character set that has the

   same character code number as the OEM character is displayed.

MORE INFORMATION

================

OEM and ANSI Character Sets

---------------------------

MS-DOS uses the OEM character set. This character set varies between

computers and depends on the code page ROM (read-only memory)

installed by the computer manufacturer. For example, personal

computers manufactured for use in the United States use a character

set called code page 437, while computers manufactured for use in

Portugal use code page 860. MS-DOS uses the OEM character set in

applications and to create files and filenames.

For the most part, Windows uses fonts organized according to the ANSI

character set (called ANSI-set fonts, in this article). Windows also

supports fonts that use the same OEM character set that MS-DOS uses

(called OEM-set fonts, in this article).

Character positions 32 through 127 are identical in the ANSI and OEM

character sets for most code pages (including code pages 437, 850,

852, 860, 861, and 865). The remaining characters of the OEM character

set (character positions 0 through 31 and 128 through 255) either do

not appear in the ANSI character set, or exist at a different position

in the ANSI character set. Therefore, some characters in the OEM

character set cannot be displayed in Windows using an ANSI-set font.

If an application must display such characters under Windows, an OEM-

set font is required.

Typing ANSI and OEM Characters in Windows

-----------------------------------------

In the Windows environment, a user can enter any character in the

character set by holding down the ALT key and typing 0xxx, where "xxx"

is the decimal number of the desired character position in the font.

For example, with an ANSI-set font in use, ALT+0123 will display the

123rd character in the ANSI character set. Similarly, with an OEM-set

font in use, ALT+0123 will display the 123rd character in the OEM

character set.

In the MS-DOS environment, a user can enter any character in the OEM

character set by holding down the ALT key and typing xxx (no leading

zero), where "xxx" is the decimal number of the desired character

position in the font.

If a user enters an MS-DOS OEM character set code (ALT+xxx) in an

application for Windows that uses an ANSI-set font, Windows converts

the OEM-set character to the character that most closely matches in

the ANSI set. This conversion is governed by a mapping table that is

installed with Windows. Because some OEM-set characters with positions

greater than 127 do not exist in the ANSI character set, the result of

the conversion in Windows may differ from the character in the OEM

set. The OemToAnsi function uses the same mapping table to perform its

character conversions.

For example, while OEM character-set code page 437 contains a square-

root symbol at position 251, the ANSI character set does not contain

this character. Consequently, when the user types an ALT+251 in an

edit control that uses the ANSI character set, an underscore character

appears because Windows defines the character mapping in this manner.

As another example, the C-cedilla character exists in both the ANSI

character set and in the OEM character-set code page 437. Therefore,

typing ALT+128 in an edit control creates the desired C-cedilla

character. Note that while the character exists in both character

sets, its position is different in each set (128 in the OEM character

set and 199 in ANSI). The alternative method to request a C-cedilla is

to type ALT+0199, which specifies the character's position in the ANSI

character set.

An edit control that uses the ES_OEMCONVERT style and a combo box that

uses the CBS_OEMCONVERT style have a different behavior from that

described above. These two styles cause their text contents to be

converted from lowercase letters to uppercase letters, then from the

ANSI set to the OEM set and then back to the ANSI set for display.

This behavior is important for an edit control in which the user

specifies a filename. If the user enters characters that do not exist

in the underlying OEM character set, the name of the file will differ

from the name specified by the user, which would be confusing. Because

the characters are mapped into characters that exist in the OEM

character set, the filename specified always matches the filename

actually used. The contents are converted to uppercase characters

because it is customary in some languages to eliminate diacritical

marks when a character is in uppercase, and the OEM character set does

not contain uppercase characters with these diacritical marks.

Displaying a String Containing OEM-Set Characters

in an Application that Uses the ANSI Character Set

--------------------------------------------------

Text editors running under MS-DOS use the OEM character set for

display and in the files they create. When a Windows-based text editor

loads a file that uses the OEM character set, the editor interprets

the characters according to the ANSI character set. Character

positions 32 through 127 are not affected under most code pages

because both the ANSI and OEM character sets have identical

characters. However, character positions greater than 127 may be

displayed differently than in the MS-DOS-based text editor because the

character positions represent different characters in the ANSI

character set.

The solution to this difficulty is to use a Windows-based text editor

that uses the ANSI character set when the text contains characters in

both the OEM and ANSI character sets. A Windows-based editor accepts

ANSI-set characters directly and converts OEM-set characters to the

closest matching ANSI-set characters. The resulting text contains only

ANSI-set characters, which can be displayed by any application running

under the Windows environment. If an application must display OEM-set

characters that are not in the ANSI character set, it must use an OEM-

set font.

Consider the following example: An MS-DOS-based text editor is used to

edit a application's resource file on a system with OEM character-set

code page 437 installed. The user types ALT+129 as part of the static

text to label a button in a dialog box. However, when the dialog box

is displayed, the text is not as expected but contains a black

rectangle where the u-umlaut character belongs. The black rectangle is

used to signify character positions that are not defined in the ANSI

character set.

To workaround to this problem is to edit the resource file with a

Windows-based text editor that uses the ANSI character set. Typing

ALT+129 will create a u-umlaut as desired because the editor will

convert the OEM-set character to the closest matching ANSI-set

character. In this case OEM-set character position 129 maps to ANSI-

set character position 252. The alternative method to specify u-umlaut

in the Windows-based editor is to type ALT+0252, using its ANSI

character set character position directly.

As another example, an application requires the square-root symbol,

which does not exist in the ANSI character set, as part of a button

label. Assuming the code page 437 is installed, and that the resource

file is edited under Windows, enter ALT+0251 in the button label

because the square-root symbol is the 251st character of the OEM

character set. When the application is run, send a WM_SETFONT message

to the control, specifying an OEM-set font. An OEM-set font is always

available from the GetStockObject function through its OEM_FIXED_FONT

index.

For more information on code pages and character sets under Windows,

query on the following words in the Microsoft Knowledge Base:

   prod(winsdk) and code and pages and character and sets

For a reference to a Windows Developer's Note regarding this subject,

query on the following word in the Microsoft Knowledge Base:

   INTLAPPS

Additional reference words: 3.00 3.10 folding

KBCategory: kbprg

KBSubcategory: UsrLoc WintlDev


Implementing the Drag-Drop Protocol

Article ID: Q83543

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows 3.1 supports four new functions and one new message that

enable an application to implement the drag-drop protocol. DRAGDROP is

a file in the Software/Data Library that demonstrates using all four

functions and the message. When the user drags and drops a file onto

DRAGDROP, the name of the file is added to a list box in DRAGDROP.

Download DRAGDROP.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for DRAGDROP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DRAGDROP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DRAGDROP.EXE

MORE INFORMATION

================

An application that can accept files dragged from the File Manager

calls the DragAcceptFiles function specifying one or more of its

windows. When the user drags a file from the File Manager into the

window specified in the DragAcceptFiles call, and releases the left

mouse button, File Manager sends the application a WM_DROPFILES

message. (File Manager sends a WM_DROPFILES message only to

applications that have registered a window with DragAcceptFiles.)

One of the parameters to WM_DROPFILES contains a handle to an internal

data structure. The DragQueryFile function retrieves a number of

dropped files and their names from the data structure and returns this

information to the application. Likewise, DragQueryPoint retrieves the

position of the mouse cursor when the file(s) was dropped.

To release the memory allocated by Windows for the WM_DROPFILES data

structure, the application must call the DragFinish function after it

retrieves the applicable data.

Additional reference words: 3.10 softlib DRAGDROP.exe

KBCategory: kbprg kbfile

KBSubcategory: UsrDnd


CONVINFO Data Structure wStatus Field Description

Article ID: Q83916

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

The documentation for the CONVINFO data structure used by the Dynamic

Data Exchange Management Library (DDEML) lists the possible values of

the structure's wStatus field. However, the documentation does not

elaborate on the causes of these different values.

The following table lists the various values of the wStatus field and

the conditions under which each status code is reported:

   wStatus        Cause

   -------------------------------------------------------------------

   ST_ADVISE      One or more links are in progress.

   ST_BLOCKED     The conversation is blocked.

   ST_BLOCKNEXT   The conversation will block after calling the next

                  callback.

   ST_CLIENT      The conversation handle passed to the

                  DdeQueryConvInfo function is a client side handle.

                  If the ST_CLIENT value is 0, then the conversation

                  handle passed to the DdeQueryConvInfo function is a

                  server side handle.

   ST_CONNECTED   The conversation is connected.

   ST_INLIST      The conversation is a member of a conversation list.

   ST_ISLOCAL     Both sides of the conversation are using the DDEML.

   ST_ISSELF      Both sides of the conversation are using the same

                  instance of the DDEML.

   ST_TERMINATED  The conversation has been terminated by the other

                  side.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


PRB: Vertical Bars Displayed in Message Box, Control Text

Article ID: Q84900

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application runs under Windows 3.0, text in a message box or in a

child-window control appears on two lines, as desired. However, under

Windows 3.1, the same text appears as one line with two vertical bars at

the position where the line break should appear.

CAUSE

=====

The character sequence "\n\r" was used to separate the two lines of text.

RESOLUTION

==========

Modify the text to use the character sequence "\r\n" to break lines of

text.

MORE INFORMATION

================

In an application developed for the Windows environment, various text

strings can contain an embedded carriage return-linefeed pair to display

the text on two separate lines. For example, an application can send the

following message to a multiline edit control in a dialog box to display

the string "This is a test" on two lines with a break between the words "a"

and "test":

   SetDlgItemText(hDlg, IDC_MEDIT, (LPSTR)"This is a\r\ntest."));

Under Windows 3.0, both the "\r\n" and "\n\r" strings create a new line in

the output text. However, under Windows 3.1, only the "\r\n" string creates

a new line in the output. The "\n\r" string creates the two vertical bars

discussed above.

Additional reference words: 3.00 3.10 static

KBCategory: kbprg kbprb

KBSubcategory: UsrDlgs


Multiple Document Interface Enhancements in Windows 3.1

Article ID: Q85010

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The Windows multiple document interface (MDI) provides a way to

standardize the user interface of applications that can process more

than one "document" simultaneously. Applications that use MDI

automatically benefit from improvements in the MDI user interface code

within Windows.

The MDI under Windows version 3.1 introduces a number of significant

enhancements to the features provided by Windows version 3.0, and it

also removes a number of problems. When an application that is

designed to use MDI under Windows 3.0 is run on a system equipped with

Windows 3.1, the application automatically receives the benefit of

many of these enhancements. In addition, an application targeted

specifically for Windows 3.1 can use additional new MDI features.

MORE INFORMATION

================

The Windows 3.1 MDI corrects a number of problems found in the Windows

3.0 MDI. For a list of problems in Windows 3.0 that have been

corrected in Windows 3.1, query on the following words in the Microsoft

Knowledge Base:

   buglist3.00 and fixlist3.10 and mdi

The query above provides a list of articles describing the problems

with MDI under Windows 3.0; the list also describes methods to work

around these problems. Even though an application is no longer

required to work around these problems, the methods suggested in each

article are compatible with MDI under Windows 3.1.

The "Double-Click" Controversy Finally Comes to a Close

-------------------------------------------------------

Under Windows 3.0, when the user double-clicks the mouse on the system

menu bitmap of a maximized MDI child window, the child window does not

close. This behavior caused many complaints when MDI was incorporated

into Windows 3.0. A controversy arose regarding this behavior: some

believed it to be a design choice; others saw it as a problem with the

software.

The design has been changed under Windows 3.1. Using the mouse to

double-click the system menu bitmap of a maximized MDI child window

closes the child window. The new behavior removes an inconsistency

among applications that use the MDI functions built into Windows and

two applications that perform their own MDI processing: Microsoft Word

for Windows and Microsoft Excel for Windows.

A Difference with Scroll Bars on MDI Children

---------------------------------------------

Under Windows 3.0, if an application specifies WS_HSCROLL and

WS_VSCROLL in the style field of an MDICREATESTRUCT data structure and

creates an MDI child window, the scroll bars do not appear. Windows

automatically sets the scroll range to zero when it creates the scroll

bars. The application must call the SetScrollRange function to specify

a positive, non-zero, upper bound for the scroll range to make the

scroll bars appear.

Under Windows 3.1, the application behaves somewhat differently.

Because Windows 3.1 does not reset the scroll range to zero, the

scroll bars appear if the application specifies the WS_HSCROLL and

WS_VSCROLL styles. This change might cause problems for an application

designed under Windows 3.0 that expected the scroll bars to be hidden

until the application explicitly set the scroll range.

The CS_NOCLOSE Class Style

--------------------------

Under Windows 3.0, specifying the CS_NOCLOSE window class style does

not change the behavior of MDI child windows. This behavior has been

corrected under Windows 3.1. For example, an application specifies

CS_NOCLOSE in the style field of a WNDCLASS structure and registers a

window class using that structure. If the application creates an MDI

child window using the new class, Windows will disable the Close menu

option on the child window's system menu.

However, Windows makes other changes to the MDI child's system menu

that are not correct. For more information on this problem, query on

the following words in the Microsoft Knowledge Base:

   CS_NOCLOSE and MDI

MDI Child Windows No Longer Required to Use Standard Styles

-----------------------------------------------------------

One of the most requested enhancements to Windows MDI provided by

Windows 3.1 is the ability to create MDI child windows using any

window style. If an application specifies the MDIS_ALLCHILDSTYLES

style for its MDI client window, Windows creates the MDI child windows

using only the styles specified in the MDICREATESTRUCT data structure.

Otherwise, Windows enforces the default MDI child window styles. For

example, an application that uses the MDIS_ALLCHILDSTYLES style can

create MDI child windows without maximize or minimize buttons.

Multiple Document Interface Message Changes

-------------------------------------------

Windows 3.1 includes several enhancements to MDI system messages. The

WM_MDICASCADE and WM_MDITILE messages have been enhanced to accept a

cascade flag. If an application sends either of these messages with

wParam set to MDITILE_SKIPDISABLED, Windows does not change the

position of disabled MDI child windows.

The WM_MDITILE message accepts two additional flags in wParam:

MDITILE_HORIZONTAL and MDITILE_VERTICAL. These flags specify that the

MDI child windows should be as wide as possible or as tall as

possible, respectively.

Under Windows 3.0, the WM_MDINEXT message was not accompanied by any

parameters in lParam or wParam. Under Windows 3.1, both parameters are

used. The value of wParam specifies the handle of the MDI child window

receiving the message. The lParam parameter is a Boolean value

specifying whether the next or previous MDI child window is being

activated.

The WM_MDISETMENU message also has new functionality. If wParam

contains the Boolean value TRUE, the current menus are refreshed. If

wParam contains the Boolean value FALSE, the frame menu and window

menu are replaced with the menus specified in lParam.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrMdi


ODVHLB Demonstrates Owner-Draw Variable-Height List Box

Article ID: Q86333

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

ODVHLB is a file in the Microsoft Software Library that demonstrates using

an owner-draw variable-height list box in an application for the Microsoft

Windows environment.

In the ODVHLB application, the user can add a short string (one line

of text), long string (two lines of text), or an icon to a list box.

Because the list box has the LBS_MULTIPLESEL style, the user can

select multiple items in the list box simultaneously.

Download ODVHLB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ODVHLB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ODVHLB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ODVHLB.EXE

MORE INFORMATION

================

To implement an owner-draw variable-height list box, an application

must process the WM_MEASUREITEM and WM_DRAWITEM messages in the window

procedure for the list box's parent window. When the list box has the

LBS_OWNERDRAWVARIABLE style, the parent window receives a

WM_MEASUREITEM and a WM_DRAWITEM message each time the application

updates an item in the list box.

When the parent of the list box receives a WM_MEASUREITEM message,

lParam points to a MEASUREITEMSTRUCT data structure. The application

must specify values for the itemHeight and itemWidth members of this

structure to indicate how much space in the list box Windows must

allocate for the item. Through the WM_MEASUREITEM message, the

application can individually specify the height of each item in the

list box.

The parent of the list box receives a WM_DRAWITEM message when an item

in the list box needs to be drawn. The lParam parameter points to a

DRAWITEMSTRUCT data structure. The itemAction member indicates the

required drawing action and itemState member indicates the visual

state of the item. For example, when the itemAction member is

ODA_SELECT and the itemState member has the ODS_SELECTED flag set, the

selection state has changed and the item is gaining selection.

Conversely, if the itemState member has the ODS_SELECTED flag clear,

the item is losing selection.

The itemData member of the DRAWITEMSTRUCT data structure identifies

the item in the list box, either through a pointer to a string or a

32-bit identifier. An application specifies an appropriate identifier

when it uses the LB_ADDSTRING or LB_INSERTSTRING message to add an

item to the list box.

Additional reference words: 3.10 listbox softlib ODVHLB.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


Program Manager DDE Command AddItem Documentation

Article ID: Q86872

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Windows Program Manager has a dynamic data exchange

(DDE) command-string interface that allows another application to

create, update, and delete groups and programs within groups. The text

below extends the documentation for the AddItem command that begins on

page 373 of the "Microsoft Windows Software Development Kit:

Reference, Volume 1: Overview."

MORE INFORMATION

================

The syntax for the AddItem command has the following form:

   AddItem(CmdLine[, Name[, IconPath[, IconIndex[, xPos, yPos[,

           DefDir[, HotKey[, fMinimize] ] ] ] ] ] ])

The AddItem command instructs Program Manager to add an icon to an

existing group.

If you specify fewer than four parameters, the IconIndex defaults to

the last icon in the group. For example:

   AddItem(notepad.exe, "Notepad", notepad.exe)

If you specify five or more parameters but do not specify values for

xPos and yPos, the icon position defaults to 0, 0 (the first icon in

the group). For example:

   AddItem(notepad.exe, "Notepad", notepad.exe,,,, "c:\")

Therefore, to create the last icon in the group and specify five or

more parameters, set xPos and yPos to -1. For example:

   AddItem(notepad.exe, "Notepad", notepad.exe,, -1, -1, "c:\")

For the HotKey parameter, specify the ASCII value of the desired key.

The application can create a key combination (for example,

ALT+SHIFT+A) by adding one or more of the following values to the

ASCII value for the key:

                Decimal

   Key           Offset

   ---           ------

   SHIFT            256

   CTRL             512

   ALT             1024

   Extended        2048

For example, ALT+SHIFT+A is signified by 1345 (1024+256+65).

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


PRB: Crash Double-Clicking File in Open or Save Common Dialog

Article ID: Q87536

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In an application developed for the Microsoft Windows environment with the

Open or Save common dialog box, when the user double-clicks a filename in

the dialog box, the application crashes. However, when the user selects a

filename and chooses the OK button, the operation succeeds.

CAUSE

=====

Because the amount of space reserved for the application's stack is

insufficient, the application overwrites part of its data segment when

calling GetOpenFileName() or GetSaveFileName().

RESOLUTION

==========

Modify the application's module definition (.DEF) file to specify at least

8192 bytes for the stack.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrCmnDlg


PRB: DLL System Hook Function Not Affecting Apps System-Wide

Article ID: Q88190

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When you are trying to install a system hook function with

SetWindowsHookEx in a dynamic-link library (DLL), the hook function

is executed only within the calling application even though it is

supposed to affect all applications system-wide.

CAUSE

=====

In Windows 3.0, the minimum required compile option to generate the

appropriate entry/exit code sequence for a Windows-based application is

the /Gw switch.

With Microsoft C/C++ version 7.0, however, the documentation states

that the /Gw and /GW switches should be used only for applications

that must run in real mode Windows. Because real mode is no longer

available in Windows 3.1, most programs should now be built using

the /GA switch (/GD for DLLs). The C 7.0 /GA and /GD switches

require that exported functions (especially callback functions) be

explicitly marked as __export if the switch is to affect them.

RESOLUTION

==========

If the DLL containing the hook function is compiled with the /GD

switch, the hook function should be explicitly marked with the

__export keyword:

   LRESULT FAR PASCAL __export CbtFunc (int Code,

                                        WPARAM wParam, LPARAM lParam);

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrHks


WM_PAINTICON Message Removed from Windows SDK Docs

Article ID: Q88192

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The WM_PAINTICON message is not listed in the "Programmer's Reference,

Volume 3: Messages, Structures, and Macros" for version 3.1 of the

Microsoft Windows Software Development Kit (SDK). The text below

explains this decision and provides source code that enables an

application to paint its own icon.

MORE INFORMATION

================

When an application for the Microsoft Windows operating system

registers a window class, it specifies a handle to an appropriate icon

in the hIcon member of the WNDCLASS data structure. This can be an

application-specific icon loaded from the application's resources or

the default application icon provided with Windows.

If the application includes its own icon, Windows sends a WM_PAINTICON

message when the user minimizes the application. If the application

passes the WM_PAINTICON message to the DefWindowProc function, Windows

paints the icon in the appropriate location.

If the application specifies the default icon or no icon, Windows does

not send a WM_PAINTICON message when the user minimizes the

application; instead, it sends a WM_PAINT message. When the

application receives the WM_PAINT message, it can either pass the

message to DefWindowProc so that Windows will paint the default icon,

or the application can paint the icon dynamically.

Because the application cannot process the WM_PAINTICON message,

except to pass it to DefWindowProc, it has been removed from the

documentation for version 3.1 of the Windows SDK.

The following code demonstrates how to process the WM_PAINT message to

paint the icon. Given a window handle, the IsIconic function indicates

whether the window is an icon:

   case WM_PAINT:

      {

      PAINTSTRUCT ps;

      BeginPaint(hWnd, &ps);

      if (IsIconic(hWnd))

         {

         SendMessage(hWnd, WM_ICONERASEBKGND, (WORD)ps.hdc, 0);

         DrawIcon(ps.hdc, 0, 0, hIcon);

         }

       EndPaint(hWnd, &ps);

       }

       break;

When the application processes the WM_QUERYDRAGICON message by

returning the handle to its icon, Windows converts the icon to a

cursor when the user drags the icon window with the mouse.

   case WM_QUERYDRAGICON:

      return hIcon;

Because the application paints the icon background when it processes

the WM_PAINT message, the following code prevents the screen from

flashing:

   case WM_ERASEBKGND:

      if (IsIconic(hWnd))

         return TRUE;

      else

         return DefWindowProc(...);

      break;

DefWindowProc erases the background.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


Software Library Has DDE Management Library Information

Article ID: Q89542

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

BOUNCET is a file in the Software Library that details how to use the

Dynamic Data Exchange Management Library (DDEML) to perform dynamic

data exchange (DDE) in an application developed for the Microsoft

Windows environment.

Download BOUNCET.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BOUNCET.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BOUNCET.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BOUNCET.EXE

Additional reference words: 3.00 3.10 softlib BOUNCET.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


Buttons and Cursors Documentation and Sample

Article ID: Q89562

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

BTTNCUR.EXE is a file in the Microsoft Software Library that contains

information about using buttons and cursors in the Microsoft Windows

graphical environment. BTTNCUR.ZIP contains the source code to a

dynamic-link library (DLL) that contains 15 new standard cursors and 9

standard command images to use as buttons on an application's toolbar.

Other code in the DLL draws a button using one of these images (or

another image provided by an application) in one of six different

states. With this code, an application can provide only one image for

a button and dynamically create other states at run time. This

dramatically reduces the storage required for an application to

provide a button-rich graphical interface.

Download BTTNCUR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BTTNCUR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BTTNCUR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BTTNCUR.EXE

NOTE: The BTTNCUR.EXE file contains a directory structure. To reproduce the

directory structure, specify the -d option as follows:

   buttncur -d

Additional reference words: 3.10 softlib BTTNCUR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


Both Windows in SetParent() Call Must Belong to Same Task

Article ID: Q89563

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

A Windows-based application can use the SetParent() API to change the

parent window for a pop-up, overlapped, or child window. However, the

windows identified by the hwndChild and hwndNewParent parameters must both

be created by the same instance of the same application.

In a Win32-based application, it is possible to use SetParent() to change

the parent window.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrWndw


PRB: Common Dialog Box Hook Function Cannot Access Variables

Article ID: Q89566

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

----------------------------------------------------------------------

SYMPTOM

=======

In an application developed for the Microsoft Windows environment using a

common dialog box and a dialog box hook function, the hook function is

unable to access global or local variables even though it receives

messages.

CAUSE

=====

Because the hook function is not exported in the application's module

definition (.DEF) file, the hook function's data segment is not set

correctly when functions in the common dialog box library (COMMDLG.DLL)

call the hook function.

RESOLUTION

==========

Modify the .DEF file to list the hook function in the EXPORTS section.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrCmnDlg


Handling WM_QUIT While Not in Primary GetMessage() Loop

Article ID: Q89738

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

An application can terminate while in a message loop that is different

from the primary GetMessage() loop. If this secondary message loop

retrieves the WM_QUIT message from the message queue, the message must

be reposted so that the primary GetMessage() loop can exit.

MORE INFORMATION

================

An application can get into a secondary message loop that is different

from the primary GetMessage() loop in order to track drag messages,

yield periodically during lengthy processing, and so on. The user may

be able to terminate the application while the secondary message loop

is being used to retrieve messages from the message queue.

If the GetMessage()/PeekMessage() call used in the secondary loop

specifies a message filter that does not include WM_QUIT, WM_QUIT will

not be retrieved from the message queue. When the loop terminates,

control will be returned to the primary GetMessage() loop, which will

retrieve the WM_QUIT message.

If the GetMessage()/PeekMessage() call in the secondary loop retrieves

all messages or specifies a message filter that includes the WM_QUIT

message, the WM_QUIT message that is retrieved must be reposted and

control must be returned to the primary message loop. The primary

message loop will then retrieve the reposted WM_QUIT message and exit.

while (bNotDone)

{

   // Secondary message loop

   while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

   {

      if (msg.message == WM_QUIT)

      {

         // Repost the QUIT message so that it will be retrieved by the

         // primary GetMessage() loop.

         PostQuitMessage(msg.wParam);

         return FALSE;

      }

      // Pre-process message if required (TranslateAccelerator etc.)

      TranslateMessage(&msg);

      DispatchMessage(&msg);

      :

      :

   }

   :

}

The primary message loop will not exit if the secondary message loop

does not repost the WM_QUIT message. Consequently, the application

will remain in memory even though all its windows are destroyed.

An alternative solution is to prevent the user from terminating the

application while the application is in the secondary message loop.

Additional reference words: 3.00 3.10 close

KBCategory: kbprg

KBSubcategory: UsrMsg


PRB: Accented Characters in Filename Controls Lose Accents

Article ID: Q90854

-------------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

-------------------------------------------------------------------------

SYMPTOMS

========

In an application for the Microsoft Windows graphical environment

that uses a combo box with the CBS_OEMCONVERT style or an edit

control with the ES_OEMCONVERT style, the user enters a character

with an accent mark, and the accent is lost.

CAUSE

=====

The OEMCONVERT control styles convert all input as follows:

 - Convert lowercase letters to uppercase letters with the

   AnsiUpper function.

 - Convert all characters from the ANSI character set to the

   installed OEM character set with the AnsiToOem function.

 - Convert the appropriate characters back to lowercase letters

   with the AnsiLower function.

Because the OEM character set installed in most computers (code

page 437) does not include representation for the capital letters

with accent marks, the accent marks are lost in this conversion

process. This occurs in all versions of Windows, including those

designed for use outside the United States.

RESOLUTION

==========

Unicode specifies a unified character set that can represent every

active language and many dead languages. Windows NT incorporates

support for Unicode.

MORE INFORMATION

================

For further details on the cause of this problem, see the article by

Dr. William S. Hall "Adapt Your Program for Worldwide Use with Windows

Internationalization Support," starting on page 29 of the Nov-Dec 1991

Microsoft Systems Journal.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrCtl


Is DdePostAdvise Synchronous?

Article ID: Q92540

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

The server's callback function will have received XTYP_ADVREQ for each

existing advise loop that was started without a XTYPF_ACKREQ flag, by the

time DdePostAdvise returns. So DdePostAdvise is synchronous except for

advise loops started with the XTYPF_ACKREQ flag.

MORE INFORMATION

================

The DdePostAdvise function causes the Dynamic Data Exchange Management

Library (DDEML) to send a XTYP_ADVREQ transaction to the calling (server)

application's DDEML callback function for each client that has an advise

loop active on the specified topic or item name pair. A server application

calls this function whenever the data associated with the topic or item

name pair changes.

DDEML will have sent XTYP_ADVREQ for each advise loop that was started

without a XTYPF_ACKREQ when DdePostAdvise returns.

If an advise loop was started with the XTYPF_ACKREQ flag, the server will

have to wait until the client acknowledges that it received the previous

data item. Consequently, if the client did not acknowledge the previous

data item, DdePostAdvise will set a flag for the advise loop indicating the

data change and XTYP_ADVREQ will be sent by DDEML only after the client

acknowledges the previous data item. The cAdvReq parameter of XTYP_ADVREQ

for the slow client will contain CADV_LATEACK instead of the remaining

advise loops to be processed.

This means that DdePostAdvise can return before the server callback

receives the XTYP_ADVREQ corresponding to a XTYPF_ACKREQ advise loop. This

is not a problem because when the client used XTYPF_ACKREQ, it was willing

to miss some of the data transitions in order to prevent the server from

sending it data faster than could be processed. The server can send the

slow client the latest data when it finally receives the XTYPF_ADVREQ with

cAdvReq set to CADV_LATEACK.

Additional reference words: 3.00 3.10 call back

KBCategory: kbprg

KBSubcategory: UsrDde


Setting the CAPS LOCK, SCROLL LOCK, and NUM LOCK States

Article ID: Q94606

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The current state of the CAPS LOCK, SCROLL LOCK, and NUM LOCK keys can be

queried and toggled via the Get/SetKeyboardState functions.

GetKeyboardState retrieves a byte array describing the state of every key.

If the low order bit of a toggle key is set, the key is "on." By changing

this bit, the toggle key state can be set via SetKeyboardState.

MORE INFORMATION

================

The following code fragment demonstrates how to toggle the CAPS LOCK key:

Sample Code

-----------

   BYTE bKeyState[256];

   GetKeyboardState ((LPBYTE)&bKeyState);

   if (bKeyState[VK_CAPITAL] & 1)     // Is CAPS LOCK on?

      bKeyState[VK_CAPITAL] &= 0xFE;  // Turn CAPS LOCK off.

   else

      bKeyState[VK_CAPITAL] |= 0x01;  // Turn CAPS LOCK on.

   SetKeyboardState ((LPBYTE)&bKeyState);

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrInp


PRB: DdeInitialize Fails in Implicitly-Loaded DLL's LibMain()

Article ID: Q94954

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When implementing DDEML from an implicitly-loaded dynamic-link library

(DLL), calling DdeInitialize() from the DLL's LibMain() function causes the

DdeInitialize() call to fail (that is, results to an exception 13). Moving

the call to DdeInitialize() anywhere other than LibMain() corrects the

problem.

CAUSE

=====

In DdeInitialize(), DDEML initializes its data structures, allocates

memory, and also creates windows (for its own internal use). This, of

course, causes messages to be sent to the application's message queue,

which at LibMain() time, in an implicitly-loaded DLL, does not exist yet.

These messages sent to a non-existent message queue result to an exception

13.

RESOLUTION

==========

One way to resolve this problem is to export another function in the DLL,

call it InitDDEML(), which can call DdeInitialize() and perform all

necessary initializations. This guarantees that when the function

InitDDEML() is called, the application's message queue has been properly

initialized.

Another way to resolve this problem is to keep the DdeInitialize() call in

LibMain(), but to explicitly load the DLL via LoadLibrary(). This also

ensures that the calling application's message queue exists before the call

to DdeInitialize() in LibMain().

MORE INFORMATION

================

Because an implicitly-loaded DLL is loaded into memory before the calling

application is completely loaded, LibMain(), [which is analogous to an

application's WinMain()] is called before the application's message queue

is initialized. As a result, the DLL must not call functions that send

messages to the application in LibMain().

This problem is not specific to DDEML.

Similarly, an implicitly-loaded DLL is terminated after the calling

application has been removed from memory. Therefore, nothing in the Windows

exit procedure (WEP) must require the application to exist.

Additional reference words: 3.10 3.1

KBCategory: kbprg kbprb

KBSubcategory: UsrDde


PRB: Double-Click Does Not Close Win 3.1 Maximized MDI Child

Article ID: Q95578

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Double-clicking the System menu (sometimes called the Control menu) box of

a maximized MDI (multiple document interface) child window does not close

the child window in Microsoft Windows version 3.1.

NOTE: Windows version 3.0 does not implement closing a maximized MDI child

window by double-clicking its System menu box. For a solution to this

problem, query on the following words in the Microsoft Knowledge Base:

   MDI and double-click and maximized

CAUSE

=====

In Windows version 3.1, you can close a maximized child window by double-

clicking its System menu box, but the design of this feature assumes that

the MDI client window is the first child of the MDI frame window. If the

MDI frame window has a status bar, button bar, or any other window as its

first child, double-clicking will not close the maximized child window.

RESOLUTION

==========

Create the MDI client window as the first child of the MDI frame. Create

other child windows of the MDI frame window, such as a status bar or button

bar, after creating the MDI client window; then don't change the

Z-order to make it the first child.

STATUS

======

This behavior is by design.

Additional reference words: 3.10 maximize

KBCategory: kbprg kbprb

KBSubcategory: UsrMdi


Detecting Whether a Menu Is Open

Article ID: Q96427

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

With Windows version 3.1, an application can determine whether a menu

is open in the system by calling the GetSystemDebugState function. An

application can use this information to perform its tasks without

interfering with the menu mechanism of Windows.

MORE INFORMATION

================

For example, if a background application displays a hidden pop-up

window while a menu is open in some other application, the user who

opened the menu will be confused. In this situation, the background

application must check the menu state of the system before displaying

its hidden pop-up window.

GetSystemDebugState function returns a LONG value that can be used to

determine the menu state of the system. The function can be used as

follows:

     if ( GetSystemDebugState() & SDS_MENU )

         // Yes! There is a menu open.

     else

         // No! There is no menu open.

For further information on the GetSystemDebugState function, please

see page 445 of "Microsoft Windows Software Development Kit,

Programmer's Reference, Volume 2: Functions" manual.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrMen


PRB: MAKEFILE for HOOKS Sample Implemented Incorrectly

Article ID: Q96726

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The makefile for the HOOKS sample in the Microsoft C/C++ version 7.0

Software Development Kit (SDK) contains two errors that prevent the

proper reporting of hook messages.

SYMPTOMS

========

All messages are reported as unknown, and LoadString() failures are

reported under the debug kernel of Windows.

CAUSE

=====

The parameters to the resource compiler are incorrect in the

makefile, and the .RES file is missing from one set of

dependencies.

RESOLUTION

==========

Line 68 of MAKEFILE reads as follows:

   $(DLLNAME).dll: $(DLLSRCS:.c=.obj) $(DLLNAME).def

Change it to read as follows:

   $(DLLNAME).dll: $(DLLSRCS:.c=.obj) $(DLLNAME).def $(DLLNAME).res

Line 95 of MAKEFILE reads as follows:

   $(RC) -T $(DLLNAME).dll $(DLLNAME).res

Change it to read as follows:

   $(RC) -T $(DLLNAME).res $(DLLNAME).dll

STATUS

======

This problem has been corrected in Visual C++.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrHks


Adding 3D Controls Using CTL3D.DLL

Article ID: Q97361

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Microsoft Windows version 3.0 adds three-dimensional (3-D) support for

pushbuttons, but all other controls appear two-dimensional (2-D) by

default. There is a file in the Microsoft Software Library that describes

how an application can add 3-D effects to all controls by using the CTL3D

dynamic-link library (CTL3D.DLL).

Download CTL3D.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download CTL3D.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CTL3D.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CTL3D.EXE

Additional reference words: 3.10 softlib CTL3D.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


PRB: Using HSZ in AFXEXT.H and DDEML.H

Article ID: Q98871

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When using both the AFXEXT.H and DDEML.H include files in the same

source file, the following message is received:

   error C2371: 'HSZ' : redefinition; different basic types

CAUSE

=====

The problem is a naming conflict between Dynamic Date Exchange

Management Library (DDEML) and Visual Basic eXtension (VBX) files

controls, in which both use the type HSZ [handle to a string that is

zero (NULL) terminated] but with with different meanings.

AFXEXT.h includes the definition of HSZ in order to support the

Control Development Kit (CDK), and DDEML.H uses HSZ as a string type.

RESOLUTION

==========

Workarounds for this problem include:

 - Separate the DDEML and VBX code into different files, thus

   preventing AFXEXT.H and DDEML.H from being included in the same source

   file.

 -or-

 - Use #define NO_VBX_SUPPORT in the file that implements DDE. This

   will cause DDEML's definition of HSZ to be used.

Additional reference words: 3.10 c2371

KBCategory: kbprg kbprb

KBSubcategory: UsrDde


PRB: Using ToAscii() in Journal Record Hooks

Article ID: Q99337

-----------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

-----------------------------------------------------------------

SYMPTOMS

========

When a journal record hook procedure calls the ToAscii() function,

dead keys are apparently no longer processed correctly due to a side

effect.

CAUSE

=====

The current implementation of ToAscii() determines whether the key

that is currently being processed is a dead key; if yes, it collapses

the next keystroke seen in the input stream with the dead key for

Windows to display. This assumption is being made for Windows, which

calls the ToAscii() function during normal processing of keystrokes.

Calling ToAscii() in a journal record hook clears the flag that

indicates the presence of a dead key; thus, the key combination will

not be displayed correctly on the screen although it will appear

correctly when the recorded key strokes are played back.

RESOLUTION

==========

The journal record hook procedure should call the ToAscii() function

twice with the same parameters when processing a dead key [that is,

the call to ToAscii() returns -1]. This will reset the dead key flag

internally.

Note that the source code for the ToAscii() function is publicly

available because it resides in the keyboard device driver whose

source is shipped with the Windows Device Development Kit (DDK).

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrHks


Windows 3.1 Card File Format

Article ID: Q99340

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article documents the file format used by Microsoft Windows

version 3.1 Cardfile. Please note that the Cardfile file format (.CRD)

may change in future versions. All numbers in this document, including

those in the descriptive text, should be interpreted as hexadecimal

numerals. All data pointers and count bytes in the file are unsigned

binary/hexadecimal integers in least-to-most significant format. All

text in the file is saved in low ASCII format. In the text section of

a card's data, <CR> is always followed by <LF>.

MORE INFORMATION

================

The Cardfile file format is as follows:

   Byte #  Description

   -------------------

   0 - 2   Signature bytes--always "RRG" (52 52 47).

   3 - 6   Last object's ID.

   7 - 8   Number of cards in file.

Beyond the first 9 bytes are the index lines--the information about

the top line of each card. The first index entry begins at byte 9 in

the file, and successive entries begin 34 bytes after the beginning of

the last index entry (the second entry at byte 3D, the third entry at

byte 71, and so forth). The format for each index line entry is as

follows:

   Byte #  Description

   -------------------

   0 - 5   Null bytes, reserved for future use (should all be 00).

   6 - 9   Absolute position of card data in file.

   A       Flag byte (00).

   B - 32  Index line text.

   33      Null byte; indicates end of index entry.

After the last index entry, each card's data is stored. Card data is

in one of four general formats: graphic and text, text only, graphic

only, and blank. Blank cards consist of 4 null bytes; the other card

formats are below:

   Graphic       Text     Graphic

   & Text        Only     Only

   -------------------------------------------------------------------

   0 - 1        0 - 1#    0 - 1         Flag Determining whether or not

                                        the card contains an object.

   2 - 5          *       2 - 5         Unique object ID.

   6 - x          *       6 - x         The OLE object.

   x+1 - x+2      *       x+1 - x+2     Character width, used for device

                                        independence.

   x+3 - x+4      *       x+3 - x+4     Character height.

   x+5 - x+C      *       x+5 - x+C     RECT: left  - X-coordinate of the

                                                      upper-left corner.

                                              top   - Y-coordinate of the

                                                      upper-left corner.

                                              right - X-coordinate of the

                                                      lower-right corner.

                                              bottom- Y-coordinate of the

                                                      lower-right corner.

   x+D - x+E      *       x+D - x+E     Object type embedded=0, linked=1,

or

                                        static=2 (values may change in the

                                        future).

   x+F - x+10   2 - 3     x+F - x+10#   Length of text entry.

   x+11 - y     4 - z         *         Text.

NOTE:

   x = 6 + size in bytes of the entire OLE object (the entire size of the

       object is not stored anywhere within the .CRD file). See below for

       more information on the OLE object size.

   y = x + 10 + length of text entry.

   z = 3 + length of text entry.

   # - These bytes are null if no object/text.

   * - These bytes do not exist if no object/text.

The first byte of any card's data entry is pointed to by bytes 6-9 in

the index entry. Note that no null byte is used to indicate the end of

the card's data entry; the next card's data entry immediately follows

the last byte of the previous entry, which is null only if the

previous card has no text (null length of text entry).

OLE Object

----------

The size of the OLE object is not stored anywhere within the .CRD

file. The OLE object could be loaded using OleLoadFromStream();

however, to get passed the OLE object, the file needs to be parsed.

The OLE object's format description is documented in Appendix C of the

"Object Linking and Embedding Programmer's Reference" version 1.0,

published by Microsoft Press, and also in the Microsoft Windows

Software Development Kit (SDK) "Programmer's Reference, Volume 1:

Overview," Chapter 6, Object Storage Format. Below is an algorithm

that uses the OLE object's format description to parse the OLE object

in the .CRD file and pass it.

Need Five Primary Functions

---------------------------

   Primary Function        Description

   -----------------------------------

   ReadLong()            - Reads a long from the file and advances the file

                           pointer.

   EatBytes(NumBytes)    - Reads and discards the specified number of bytes

                           from the file and advances the file pointer.

   RdChkVer()            - Reads the version number and advances the file

                           pointer and returns TRUE if version is 1.0. To

                           check the version number, the received value

must

                           be converted to Hex then checked against 0x0100.

                           (See below for the algorithm of this function.)

   RdChkString()         - Reads the string and checks the value to see if

                           it is either METAFILEPICT, BITMAP, or DIB, then

                           returns TRUE; otherwise, returns FALSE. Advances

                           the file pointer too.

   SkipPresentationObj() - Reads and skips the variable-length presentation

                           object at the end of each object type.

                           (See below for the algorithm of this function.)

Algorithm to Skip Over the OLE Object

--------------------------------------

if (RdChkVer)                  // If the version is 1.0

  Format = ReadLong();         // 1==> Linked, 2==> Embedded, 3==> Static

  EatBytes(ReadLong());        // Class String

  if (Format == 3)             // Static object

    ReadLong();                // Width in mmhimetric.

    ReadLong();                // Height in mmhimetric.

    EatBytes(ReadLong());      // Presentation data size and data itself.

  else                         // Embedded or linked objects.

    EatBytes(ReadLong());      // Topic string.

    EatBytes(ReadLong());      // Item string.

    if (Format == 2)           // Embedded object.

      EatBytes(ReadLong());    // Native data and its size.

      SkipPresentationObj()    // Read and eat the presentation object.

    else                       // Linked object.

      EatBytes(ReadLong());    // Network name.

      ReadLong();              // Network type and net driver version.

      ReadLong();              // Link update options.

      SkipPresentationObj()    // Read and eat the presentation object.

SkipPresentationObj()

---------------------

if (RdChkVer)                  // If the version is 1.0

  ReadLong();                  // Format ID

  if (RdChkString())           // if Class String is either

                               // METAFILEPICT or BITMAP or DIB.

    ReadLong();                // Width in mmhimetric.

    ReadLong();                // Height in mmhimetric.

    EatBytes(ReadLong());      // Presentation data size and data itself

  else

    if (!ReadLong())           // if Clipboard format value is NULL

      EatBytes(ReadLong());    // Read Clipboard format name.

    EatBytes(ReadLong());      // Presentation data size and data itself.

RdChkVer()

----------

OLEVer = ReadLong();

OLEVer = (((WORD)(LOBYTE(OLEVer))) << 8 | (WORD) HIBYTE(OLEVer);

if (OLEVer == 0x0100)           // Always use Hex value.

  return TRUE;

else

  return FALSE;

Additional references: 3.10

KBCategory: kbprg

KBSubCategory: UsrFmt


How to Use Network DDE

Article ID: Q100363

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

--------------------------------------------------------------------

SUMMARY

=======

With Windows for Workgroups, an application can use Dynamic Data

Exchange (DDE) over a network (NetDDE).

When using normal DDE or DDEML in an application, the various

fields were set up as follows (using Excel as an example):

  APPLICATION       TOPIC     ITEM

  Excel             System     Topics

However, to start a DDE conversation over the network, a client

application must establish the DDE conversation with another machine

by specifying the following strings for the application name and topic

   application:   \\machine-name\NDDE$

   topic:           share-name

where the share name is defined in the [DDEShare] section of

SYSTEM.INI. The default installation of Windows for Workgroups

contains the following DDEShares:

   [DDEShares]

   HEARTS$=mshearts,hearts,,15,,0,,0,0,0

   CLPBK$=clipsrv,system,,31,,0,,0,0,0

   CHAT$=winchat,chat,,31,,0,,0,0,0

MORE INFORMATION

================

To illustrate how to use NetDDE, ClipBook will serve as a server

example.

The following are specifics about ClipBook:

   Title Bar Caption    = ClipBook Viewer,

   Executable File Name = Clipbrd.exe,

   DDE Application Name = clipsrv,

   DDE Share Name       = CLPBK$

To start a conversation with ClipBook from your application, use the

following strings:

   APPLICATION             TOPIC        ITEM

   \\machine-name\NDDE$    CLPBK$     Topics

Under normal DDE, this would be viewed as:

   SERVER NAME       APPLICATION       TOPIC     ITEM

   \\machine-name    Clipsrv           System     Topics

This will return a list of SHARED "objects" in the ClipBook. Now that

you have a list of objects, the next step is to query the types of

formats available. For example, assume that "$Test" was returned as an

object. To find a list of formats, start a new conversation with

ClipBook with the following parameters:

   APPLICATION             TOPIC           ITEM

   \\machine-name\NDDE$    $Test           FormatList

This will return a list of the formats, each starting with the "&"

symbol (for example, CF_TEXT will return "&Text").

Using the object name and format type, it is possible to make a

connection to the server and return the contents of the topic. The

last set of parameters is:

   APPLICATION             TOPIC           ITEM

   \\machine-name\NDDE$    $Test           &Text

If your application wants to share information via NetDDE, use the

ClipBook program or call one of the NetDDE application programming

interfaces (APIs), which will create an entry in the [DDEShares]

section of SYSTEM.INI. This procedure allows other users to access

your information.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrNetDde


.PIF File Format Unavailable

Article ID: Q101416

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.0 and

   3.1

--------------------------------------------------------------------

The program information file (PIF) format for the Windows graphical

environment is unavailable. PIF files are internal system files, and

the format of these files will not be published. The format has

changed with each version of the Windows interface and will continue

to change in the future.

Additional reference words: 3.00 3.10

KBCategory: kbtool

KBSubcategory: UsrFmt


Changes Between Win 3.1 and WFW 3.1 Versions of DDEML

Article ID: Q102572

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

--------------------------------------------------------------------

The following changes have been made from the Windows 3.1 version of

DDEML to the version that shipped with Windows for Workgroups (WFW)

version 3.1:

 - The default shutdown timeout was changed from 3,000 milliseconds to

   30,000 milliseconds.

 - DdeQueryConvInfo() added support for the new hwnd and hwndPartner

   fields.

 - DdeQueryConvInfo() added more robust handling for improper setting

   of the CONVINFO structure's cb field when called.

 - Rewrote DdePostAdvise() to supply the correct count of remaining

   transactions to be processed on the same topic!item!format name set

   for the XTYP_ADVREQ transaction.

 - Disallow synchronous calls if the application is shutting down, or

   if already in the middle of a synchronous transaction.

 - DdeUninitialize() was fixed to defer processing if called while in

   the middle of a synchronous transaction.

 - DdeUninitialize() was fixed to dispatch any pending DDE messages and

   to make necessary callbacks before quitting.

 - Added call to DdeUninitialize() from within DdeClientTransaction()

   when in the middle of a synchronous transaction and

   DdeUninitialize() had been called.

 - Allow any instance to call DdeCreateStringHandle().

 - Have DdeAbandonTransaction() only mark abandoned transactions,

   rather than trying to remove the transaction from internal

   structures.

 - Alter PostMessage() overflow queuing to queue based on target

   instead of on the same task, so that one target queue overflow does

   not bog down all PostMessage() calls.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


Obtaining Group/Item Info from ProgMan Using DDEML

Article ID: Q102575

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and

   3.1

--------------------------------------------------------------------

SUMMARY

=======

Dynamic-data exchange (DDE) can be used to obtain group and/or item

information from Program Manager. Many applications, especially setup

applications, need this information before items or groups are

added/deleted from Program Manager. Information such as group names,

group filenames, the number of items in a group, an item's working

directory, title, xpos, ypos, and so forth, can be obtained very

easily from Program Manager via DDE. This article discusses how to

obtain this type of information from Program Manager using DDEML.

MORE INFORMATION

================

Program Manager is a DDEML server that provides DDE client

applications with valuable information regarding group windows and

items inside the group windows.

DDEML client applications have to connect to Program Manager with

PROGMAN/PROGMAN as SERVICE/TOPIC names. (Program Manager also supports

SHELL/APPPROPERTIES service/topic names.) Once connected, the client

application needs to REQUEST group/item information from Program

Manager by issuing a request transaction.

Group Information

-----------------

To obtain names of all the groups currently in Program Manager, the

client has to issue a request transaction with the item name set to

"GROUPS". The request has to be made in CF_TEXT format.

The return value from this transaction is a data handle that contains

the names of all the groups in Program Manager. Each group name is

separated by a carriage return (\r\n). Below is sample code that

requests names of all the groups from Program Manager:

        ghszItem = DdeCreateStringHandle(idInst,"GROUPS",

 CP_WINANSI);

        hProgData = DdeClientTransaction(NULL,

// pointer to data to pass

                                                  // to server

                        0,            // length of data

                        ghszConv,     // handle to conversation

                        ghszItem,     // handle to item-name

                                                  // string

                        CF_TEXT,      // clipboard format

                        XTYP_REQUEST, // transaction type

                        5000,         // transaction timeout

                        NULL);       // pointer to result

     retVal =  DdeGetData(hProgData, (void FAR*)szBuffer,

                             sizeof(szBuffer),  0) ;

        MessageBox(NULL, szBuffer, "TEST", MB_OK) ;

If there are four groups in Program Manager (for example, Main,

Accessories, SDK, and Applications), then the message-box call will

display names of all these groups, one per line.

Item Information

----------------

To obtain information regarding all the items in a group, the client

application has to issue a request transaction to Program Manager,

this time with the item name set to the name of the group. For

example, if the client application needs to find out if an item exists

in Program Manager group "Main", or if it needs to find out all the

items that are in group Main, then the call to DdeCreateStringHandle()

above must be changed to

   ghszItem = DdeCreateStringHandle(idInst,"MAIN", CP_WINANSI);

to create a string handle for the appropriate item name, Main.

The return value from this transaction is a data handle that contains

names of all the items in the group Main. A typical example of the

data inside resembles the following:

   "MAIN",C:\WINDOWS\MAIN.GRP,5,3

   "MS-DOS","DOSPRMPT.PIF",,PROGMAN.EXE,166,4,9,0,0

   "Mail","MSMAIL.EXE",,C:\WINDOWS\MSMAIL.EXE,258,2,0,0,0

   "Write","WRITE.EXE",,C:\WINDOWS\WRITE.EXE,384,48,0,0,0

   "File","WINFILE.EXE",,C:\WINDOWS\WINFILE.EXE,6,2,0,0,0

   "Brief ","B.PIF",,PROGMAN.EXE,93,49,2,0,0

Program Manager provides the list in CF_TEXT format. The fields of

group information are separated by commas. The first line of the

information contains the group name (in quotation marks), the path of

the group file, and the number of items in the group.

NOTE: The last value on line 1 is not documented in the Windows

Software Development Kit (SDK); it can be any value between 1 and 8.

This is the same value that is passed as the second param to the

ShowGroup() command. This value indicates the state of the group

window, whether minimized, active, and so forth.

In this particular case, the group window Main is currently the active

group and is maximized.

For more information on this value, please refer to the ShowGroup()

command documentation in Section 17.2.2 of the Windows 3.1 SDK

"Programmer's Reference, Volume 1: Overview."

Each subsequent line contains information about an item in the group,

including the command line (in quotation marks), the default

directory, the icon path, the position in the group, the icon index,

the shortcut key (in numeric form), and the minimize flag.

This set of information for each item corresponds to the parameters

passed to the AddItem() function when each item was added to the

group. For more information on each of these parameters, refer to the

AddItem() command documentation on Section 17.2.5 of the Windows 3.1

SDK, "Programmer's Reference, Volume 1: Overview."

Additional reference words: 3.10 GPF gp-fault

KBCategory: kbprg

KBSubcategory: UsrDde


Using the ShowGroup() Command in Program Manager

Article ID: Q102577

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and

   3.1

--------------------------------------------------------------------

SUMMARY

=======

Program Manager has a dynamic data exchange (DDE) command-string interface

that allows other applications to manipulate Program Manager's group

windows. The ShowGroup() command, in particular, can be used to instruct

Program Manager to display a specified group window minimized, maximized,

or restored. Documentation for ShowGroup() and other shell dynamic data

exchange interfaces can be found in Chapter 17 of the Windows "Programmer's

Reference, Volume 1: Overview".

MORE INFORMATION

================

The docs give the syntax for the ShowGroup() command as

   ShowGroup(GroupName, ShowCommand)

where GroupName identifies the group Window to be minimized, maximized, or

restored, and ShowCommand specifies the action that Program Manager is to

perform on the group window.

It has reported that ShowGroup() may fail if GroupName is a string. Samples

on the Microsoft Developer Network (MSDN) CD use items of type HDDEDATA and

work more reliably.

In Windows versions 3.x, ShowGroup(GroupName, 1) will not activate the

group identified by GroupName() as indicated by the docs if the group is

already in the restored (that is, normal) position. This may lead to

undesirable problems in certain cases.

For example, a setup program is trying to add some new items to a Group

called "TEST" with the following commands:

   ShowGroup(TEST,1);  // Make TEST the currently active group.

   AddItem(Item1,...); // Add items to the currently active group.

   AddItem(Item2,...);

If the group TEST is already restored but not the active group at the time

the ShowGroup() command is executed, and if some other group (such as MAIN)

is the active group, ShowGroup() fails to activate the group TEST.

Consequently, all the items added will be added to the group MAIN, not to

the group TEST as may be desired.

The workaround for this problem is to first either minimize or maximize the

group, then call ShowGroup(TEST, 1) to activate and restore the group:

   ShowGroup(TEST,2) ; // Minimize the group first so that the next time

                       // ShowGroup is called, the group is activated and

                       // restored.

   ShowGroup(TEST,1) ; // Show the group as the currently active group and

                       // activate it.

   AddItem(Item1, ..) ; //     Adds items to the right group. (TEST)

   AddItem(Item1, ..) ; //     Adds items to the right group. (TEST)

Additional reference words: 3.10 progman

KBCategory: kbprg

KBSubcategory: UsrExt


Using ReplaceItem() Command in Program Manager DDE

Article ID: Q102590

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

--------------------------------------------------------------------

SUMMARY

=======

Program Manager has a dynamic-data exchange (DDE) command-string

interface that allows other applications to manipulate its group

windows. Windows version 3.1 has a new command called ReplaceItem(),

which instructs Program Manager to delete an item and replace it with

a new item when Program Manager receives a subsequent AddItem()

command.

MORE INFORMATION

================

The syntax for the ReplaceItem() command is

   ReplaceItem(ItemName)

where ItemName is the name of the item that is to be replaced.

The ReplaceItem() command instructs Program Manager to delete the

given ItemName and record the position of the deleted item. The next

time Program Manager receives an AddItem() command, it adds the new

item to this previously recorded position, effectively replacing the

deleted item with the new one.

For example, Program Manager has a group called "MAIN" with an item

called "TEST". To replace the item TEST with a new item "NEW", the

following commands must be executed:

   ShowGroup ("MAIN", 1);    //Activate the group first.

   ReplaceItem ("TEST");

   AddItem ("NEW");

The position of the newly added item will be the same as the deleted

item (TEST) regardless of what parameters are passed in the AddItem()

command. Given that the position (xpos, ypos) of item TEST was (10,

10) in the group MAIN before it was replaced by item NEW, specifying a

new (xPos, yPos) position for NEW in the AddItem() command has no

effect. Program Manager adds the NEW item at the recorded position

(10, 10) in MAIN.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


EM_SETSEL wParam Not Used in Single Line Edit Controls

Article ID: Q102641

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

--------------------------------------------------------------------

For an edit control, the EM_SETSEL documentation states that wParam is

a flag for specifying whether to scroll the caret into view. When the

parameter is zero, the caret is scrolled into view. When the parameter

is one (1), the caret is not scrolled into view. This is only valid

for a multiline edit control. For a single line edit control, the

wParam flag is not used.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


PRB: Min/Max Boxes Do Not Work with DS_MODALFRAME

Article ID: Q102645

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

--------------------------------------------------------------------

SYMPTOMS

========

When I use the WS_MIMIMIZEBOX or WS_MAXIMIZEBOX styles in a dialog box

with a DS_MODALFRAME style, the up/down arrows are offset up and to

the right when I click them with the mouse.

CAUSE

=====

The WS_MINIMIZEBOX and WS_MAXIMIZEBOX styles cannot be used with the

DS_MODALFRAME frame style. (Menus are also incompatible with this

frame style. For more information, please see the following article in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q71499

   TITLE     : Menus Supported in Dialog Boxes w/o DS MODALFRAME Style

RESOLUTION

==========

Use a different frame style, such as WS_BORDER.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrDlgs


Dynamic Data Exchange Interface for Replacement Shells

Article ID: Q104394

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

--------------------------------------------------------------------

SUMMARY

=======

This article is a reprint of the Windows 3.1 SDK WIN31WH.HLP section

on the WinOldAp dynamic data exchange (DDE) specification.

MORE INFORMATION

================

You may choose to write an application that replaces the Windows

shell. This replacement shell must be able to provide property

information to the application that starts non-Windows programs in an

MS-DOS window. (This application is known as WinOldApp.) This section

discusses how a replacement shell can provide property information for

WinOldApp. Applications other than WinOldApp do not need this

information. The DDE protocol described in this section may not be

supported in future versions of Windows.

Properties

----------

A replacement shell should maintain several pieces of information,

called properties, for each application that WinOldApp might start.

These are the same properties that appear in the Program Item

Properties dialog box of Program Manager. These properties include:

   Description (title)

   Command line

   Working directory

   Shortcut key

   Icon

The shell must provide a DDE interface that allows WinOldApp to obtain

three of these properties: description, working directory, and icon.

To obtain its properties from the shell, WinOldApp must accomplish the

following tasks:

 - Establish a DDE conversation with the shell.

 - Request a property from the shell.

 - Receive a property from the shell.

 - Terminate the DDE conversation.

Establishing a DDE Conversation

-------------------------------

WinOldApp requests property data from the shell by using the

SendMessage function to broadcast the WM_DDE_INITIATE message. The

wParam parameter of the SendMessage function is the handle of

WinOldApp's DDE window. The low-order word of the lParam parameter is

an atom that represents the name of the shell application: "Shell".

The high-order word is an atom that represents the name of the

properties topic: "AppProperties". A "Shell" DDE server that supports

the AppProperties topic responds to the WM_DDE_INITIATE message by

sending a WM_DDE_ACK message. The server should send the following

parameters with the WM_DDE_ACK message:

   Parameter       Description

   -------------------------------------------------------------------

   hwnd            Specifies the handle of WinOldApp's DDE window. The

                   shell should use the handle that WinOldApp specified

                   as the wParam parameter in the WM_DDE_INITIATE message.

   message         Specifies the WM_DDE_ACK message.

   wParam          Specifies the handle of the "Shell" server's DDE

                   window.

   HIWORD(lParam)  Specifies an atom that represents the name of the

                   shell application: "Shell".

   LOWORD(lParam)  Specifies an atom that represents the name of the

                   properties topic: "AppProperties".

It is not necessary to free the atoms used in a conversation with

WinOldApp. It is WinOldApp's responsibility to create and free the

atoms.

Providing Property Data

-----------------------

After the DDE server that provides a replacement shell responds with a

WM_DDE_ACK message to the WM_DDE_INITIATE from WinOldApp, WinOldApp

sends a WM_DDE_REQUEST message to request property data. The server

can respond to the WM_DDE_REQUEST message by posting a WM_DDE_DATA

message.

The Windows shell associates an item name with each of the application

properties that it provides. The item names are described in the

following table:

   Item name       Description

   ---------------------------------------------------------------

   GetDescription  The shell provides an application's description

                   (title) property.

   GetWorkingDIR   The shell provides an application's

                   working-directory property.

   GetIcon         The shell provides an application's icon property.

WinOldApp requests properties by obtaining an atom for each of the

item-name strings and passing the atoms to the shell in a sequence of

WM_DDE_REQUEST messages (one message for each property). WinOldApp

also passes the handle of the application's instance as the low-order

word of the lParam parameter in the WM_DDE_REQUEST message. The shell

should use this instance handle to find the properties associated with

the application. If a "Shell" DDE server does not recognize the

application's instance handle, the server does not support properties

for the application instance. In this case, the server should respond

by sending a negative WM_DDE_ACK message. The parameters passed with

the negative WM_DDE_ACK message are as follows:

   Parameter       Description

   ------------------------------------------------------------------

   hwnd            Specifies the handle of WinOldApp's DDE window. The

                   shell should use the handle that WinOldApp specified

                   as the wParam parameter in the WM_DDE_REQUEST message.

   message         Specifies the WM_DDE_ACK message.

   wParam          Specifies the handle of the "Shell" server's DDE window.

   LOWORD(lParam)  Specifies zero. The "Shell" DDE server does not support

                   properties for the specified application instance.

   HIWORD(lParam)  Specifies an atom that represents the item name of

                   the requested property. Depending on the type of

                   property requested, the atom should identify one of

                   the following strings: "GetDescription",

"GetWorkingDIR",

                   or "GetIcon".

When WinOldApp receives a negative WM_DDE_ACK message, it terminates

the conversation with the "Shell" DDE server. If a "Shell" DDE server

recognizes the application's instance handle and the requested

property is available, it should allocate a global memory object and

copy the property data to the object. Then it should post a

WM_DDE_DATA message to WinOldApp. The WM_DDE_DATA message should

contain the handle of the global memory object.

The contents of the global memory object allocated by the shell depend

on the type of property WinOldApp requested. The following three

sections describe the description, working-directory, and icon

properties.

Providing the Description Property

----------------------------------

If the shell is responding to a request for the "GetDescription"

property, the shell should pass the following parameters with the

WM_DDE_DATA message:

   Parameter       Description

   -------------------------------------------------------------------

   hwnd            Specifies the handle of WinOldApp's DDE window. The

                   shell should use the handle that WinOldApp specified

                   as the wParam parameter in the WM_DDE_REQUEST message.

   message         Specifies the WM_DDE_DATA message.

   wParam          Specifies the handle of the shell's DDE window.

   LOWORD(lParam)  Specifies a handle to a global memory object that

                   contains a DDEDATA structure. A description of the

                   contents of the DDEDATA structure follows this table.

                   To report an error, the server should use one of the

                   error values listed with the WinExec function.

   HIWORD(lParam)  Specifies an atom that represents the string,

                   "GetDescription".

The low-order word of the lParam parameter should be a handle to a

global memory object that contains a DDEDATA structure (defined in the

DDE.H header file). The contents of the DDEDATA structure are as

follows:

#include <dde.h>

typedef struct tagDDEDATA {   /* ddedat */

    WORD    unused:12,

            fResponse:1,

            fRelease:1,

            reserved:1,

            fAckReq:1;

    short   cfFormat;

    BYTE    Value[1];

} DDEDATA;

The Value member should contain the description property, in the form

of a null-terminated string of characters from the Windows character

set. The string can be any size but typically contains fewer than 30

characters. If the server sets the fAckReq bit, WinOldApp responds to

the WM_DDE_DATA message by posting a WM_DDE_ACK message after

processing the data. If the server sets the fRelease bit, WinOldApp

frees the global memory object after copying the description string.

Otherwise, WinOldApp does not free the memory object.

Providing the Working-Directory Property

----------------------------------------

If the shell is responding to WinOldApp's request for the

"GetWorkingDIR" property, the shell passes the following parameters

with the WM_DDE_DATA message:

   Parameter       Description

   ------------------------------------------------------------------

   hwnd            Specifies the handle of WinOldApp's DDE window. The

                   shell should use the handle that WinOldApp specified

                   as the wParam parameter in the WM_DDE_REQUEST message.

   message         Specifies the WM_DDE_DATA message.

   wParam          Specifies the handle of the shell's DDE window.

   LOWORD(lParam)  Specifies a handle to a global memory object that

                   contains a DDEDATA structure. A description of the

                   contents of the DDEDATA structure follows this table.

                   To report an error, the server should use one of the

                   error values listed with the WinExec function.

   HIWORD(lParam)  Specifies an atom that represents the string,

                   "GetWorkingDIR".

The low-order word of the lParam parameter is a handle to a global

memory object that contains a DDEDATA structure. The contents of the

DDEDATA structure are as follows:

#include <dde.h>

typedef struct tagDDEDATA {   /* ddedat */

    WORD    unused:12,

            fResponse:1,

            fRelease:1,

            reserved:1,

            fAckReq:1;

    short   cfFormat;

    BYTE    Value[1];

} DDEDATA;

The Value member should specify the location (drive and path) of the

application's executable file, in the form of a null-terminated string

of characters from the Windows character set. The character string has

a maximum size of 128 characters (including the terminating null

character). If the server sets the fAckReq bit, WinOldApp responds to

the WM_DDE_DATA message by posting a WM_DDE_ACK message after

processing the working-directory property. If the server sets the

fRelease bit, WinOldApp frees the global memory object after copying

the working-directory string. Otherwise, WinOldApp does not free the

memory object.

Providing the Icon Property

---------------------------

If the shell is responding to WinOldApp's request for "GetIcon"

property, the shell passes the following parameters with the

WM_DDE_DATA message:

   Parameter       Description

   -------------------------------------------------------------------

   hwnd            Specifies the handle of WinOldApp's DDE window. The

                   shell should use the handle that WinOldApp specified

                   as the wParam parameter in the WM_DDE_REQUEST message.

   message         Specifies the WM_DDE_DATA message.

   wParam          Specifies the handle of the shell's DDE window.

   LOWORD(lParam)  Specifies a handle to a global memory object that

                   contains a DDEDATA structure. A description of the

                   contents of the DDEDATA structure follows this table.

                   To report an error, the server should use one of the

                   error values listed with the WinExec function.

   HIWORD(lParam)  Specifies an atom that represents the string,

                   "GetIcon".

The low-order word of the lParam parameter is a handle to a global

memory object that contains icon-property data. The icon data should

be in the following form:

typedef struct tagICONPROPS { /* ip */

    unsigned reserved:12,   /* reserved                         */

             fResponse:1,   /* always 1                         */

             fRelease:1,    /* 1 if app. frees object, else 0   */

             reserved:1,    /* reserved                         */

             fAckReq:1;     /* 1 if app. should respond, else 0 */

    int      cfFormat;      /* clipboard format (not used)      */

    int      nWidth;        /* width, in pixels, of the icon    */

    int      nHeight;       /* height, in pixels, of the icon   */

    BYTE     nPlanes;       /* number of planes in XOR mask     */

    BYTE     nBitsPixel;    /* number of bits/pixel in XOR mask */

    LPBYTE   lpANDbits;     /* points to AND mask array         */

    LPBYTE   lpXORbits;     /* points to XOR mask array         */

} ICONPROPS;

If the server sets the fAckReq bit, WinOldApp responds to the

WM_DDE_DATA message with a WM_DDE_ACK message after processing the

data. If the server sets the fRelease bit, WinOldApp frees the global

memory object after copying the working-directory string. Otherwise,

WinOldApp does not free the memory object.

The lpANDbits and lpXORbits pointers may be either near or far. If the

pointers are near (that is, the segment selector portion of the

pointers is zero), the bits are part of the global memory object. The

offset portion of the pointers is a near offset from byte zero of the

object. Because the bits are part of the global memory object, they

are freed along with the object. The combined size of the ICONPROPS

structure together with the bits pointed to by the lpANDbits and

lpXORbits members must be no more than 64K.

If the server needs to use far pointers for the lpANDbits and

lpXORbits members, the bits must be part of a separate memory object.

This object is not freed automatically when the global memory object

is freed.

Terminating the DDE Conversation

--------------------------------

The shell may terminate the conversation at any time by posting a

WM_DDE_TERMINATE message. After WinOldApp has obtained its properties

from the shell, it terminates the DDE conversation by posting a

WM_DDE_TERMINATE message.

Additional reference words: 3.10 dosapp winexec

KBCategory: kbprg

KBSubcategory: UsrDde


Types of System Modal Message Boxes

Article ID: Q104959

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

--------------------------------------------------------------------

SUMMARY

=======

There are two kinds of system modal message boxes:

 - Hard System Modal Message Box

   A hard system modal message box is the only window in the system

   that will receive messages.

 - Soft System Modal Message Box

   All windows owned by a soft system modal message box's task will

   receive messages. No other window in the system will receive

   messages.

MORE INFORMATION

================

If a task wants to bring up a system modal message box and requires

that messages be received by its other windows, a soft system modal

message box must be used. For example, a task may require that

WM_TIMER messages be received by a window it owns even while it

displays a system modal message box. On the other hand, a hard system

modal message box will prevent any other window in the system from

receiving messages. A hard system modal message box is also

appropriate in low memory situations because it uses very few system

resources.

Both hard and soft system modal message boxes are created using

MessageBox(). The MB_ICON* flags indicate the kind of system modal

message box to be created.

A hard system modal message box can be created using MessageBox() and

by including the following flags in the fuStyle parameter:

     MB_SYSTEMMODAL

or   MB_SYSTEMMODAL | MB_ICONHAND

or   MB_SYSTEMMODAL | MB_ICONSTOP

(Other flags such as MB_OK, MB_OKCANCEL, and so forth can also be

used. However do not use any other MB_ICON* flags).

A soft system modal message box can be created by including the

following flags in the fuStyle parameter

   MB_SYSTEMODAL | MB_ICON*

where MB_ICON* is any MB_ICON* style except MB_ICONHAND or

MB_ICONSTOP.

(Other flags such as MB_OK, MB_OKCANCEL, and so forth can also be

used. However do not use MB_ICONHAND or MB_ICONSTOP.)

Note that other tasks in the system do not receive any messages when a

task puts up a hard or soft system modal message box.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrDlgs


How to Detect Mouse and Mouse Port

Article ID: Q107693

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

A Windows-based application can use the GetSystemMetrics() function to

determine whether or not a serial mouse is connected to the computer.

However, there is no Windows application programming interface (API) to

identify the serial port of the computer that the mouse is connected to.

Instead, a Windows-based application must use the Inquire() function

documented in the Windows Device Driver Kit (DDK). You do not need the the

Windows DDK to call the Inquire() function in the MOUSE driver module.

Please see "MORE INFORMATION" for details.

Note, however, that the Inquire() function is only part of the Windows DDK

and is not a standard Windows SDK API. Because this function may change in

future versions of the Windows DDK, care must be taken in using this

function in a Windows-based application.

MORE INFORMATION

================

If GetSystemMetrics() is called with its parameter set to SM_MOUSEPRESENT,

it will indicate whether or not a serial mouse is connected. However, no

information is provide as to which port of the computer the serial mouse is

connected to.

To obtain this information, use the mouse driver function Inquire(), which

is documented in the Windows DDK "Device Driver Adaptation Guide" as

follows:

   WORD Inquire(lpMouseInfo)

   LPMOUSEINFO lpMouseInfo;

   The Inquire() function returns information about the mouse hardware.

   Parameter       lpMouseInfo

   Points to a MOUSEINFO structure containing information about the

   mouse hardware that is present, the number of buttons on the

   mouse, and the rate at which the mouse can issue interrupts.

   The MOUSEINFO structure has the following form.

   typedef struct {

     char msExist;

     char msRelative;

     short msNumButtons;

     short msRate;

     short msXThreshold;

     short msYThreshold;

     short msXRes;

     short msYRes;

     short msMouseCommPort;

   } MOUSEINFO, far *LPMOUSEINFO;

   Return Value: The return value is the number of bytes actually written

   into the MOUSEINFO structure.

   Comments: The export ordinal for this function is 1.

This function can be called from within a Windows-based application without

the presence of the DDK. To call this function, the function address must

be retrieved as follows:

   typedef WORD (FAR PASCAL * LPFNINQUIRE) (LPMOUSEINFO);

   HANDLE hMouse;

   LPMOUSEINFO lpMouseInfo;   // far pointer to MOUSEINFO struct

   LPFNINQUIRE lpfnInquire;  // function pointer to Inquire()

         if ((hMouse = GetModuleHandle ("MOUSE")) != NULL)

           lpfnInquire = (LPFNINQUIRE) GetProcAddress(hMouse, "Inquire");

Then, the Inquire() function can be called using the lpfnInquire pointer.

The msExist and msMouseCommPort parameters in the MOUSEINFO structure

provide the needed information.

Note that the mouse driver is not called MOUSE.DRV on many systems, and

therefore it is suggested that GetModuleHandle() is used to obtain the

handle to the mouse driver instead of LoadLibrary, which requires the

filename of the mouse driver.

Additional reference words: 3.10 mouse port driver detect

KBCategory: kbprg

KBSubcategory: UsrInp


Updating Multiple Device= Lines in SYSTEM.INI

Article ID: Q107695

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SUMMARY

=======

When there is more than one entry with the same name under a section in an

.INI file, WritePrivateProfileString() and WriteProfileString() can update

only the first specified entry in the section.

MORE INFORMATION

================

For example, in the [386Enh] section of the SYSTEM.INI file, there are

multiple "device=" lines. If you want to add a new device= line or update

one of the device= lines other than the first device= entry, you cannot use

WritePrivateProfileString(). For example, the following call

   WritePrivateProfileString("386Enh", "device", "drvname.drv",

   "SYSTEM.INI");

will only replace the first device= statement with DRVNAME.DRV, instead of

adding a new device= line. The reason is that the Windows .INI file

application programming interfaces (APIs) in the Windows 3.1 SDK work only

on unique entries in a given section of the .INI file.

There are couple of options available to work around this situation:

 - Open, parse, modify, and save the .INI file in your application. Note,

   that although Windows 3.1 supports direct file I/O to the INI files,

   Windows 3.0 does not. Moreover, Windows caches INI files, and therefore

   if you modify a .INI file, the disk file is updated, however, the cache

   is not. To update the cache, call WriteProfileString(NULL, NULL, NULL),

   which forces a flush of the cache.

   -or-

 - Win32 applications can use the APIs that support the multiple "entry="

   lines in a single section of a .INI file. For example, you could use the

   WriteProfileSection() and WritePrivateProfileSection() functions in the

   Win32 API.

   -or-

 - Use the VxD services that WIN386.EXE uses when it loads all the devices

   listed in the device= lines of the [386Enh] section in SYSTEM.INI file.

   The services that the VxDs provide are documented in the Windows Device

   Driver Kit (DDK).

Additional reference words: 3.10 3.00

KBCategory: kbprg

KBSubcategory: UsrIni


DdeCreateDataHandle() Memory Allocation Granularity DDEML

Article ID: Q108926

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SUMMARY

=======

The DdeCreateDataHandle function creates a global memory object and fills

the object with the data pointed to by the lpvSrcBuf parameter (second). A

DDEML application uses this function during transactions that involve

passing data to the partner application.

This application programming interface (API) allocates global memory in

multiples of 32 bytes to create data handles. If the application requests a

data handle for a buffer size that is not a multiple of 32 bytes, then

there will be some memory leak involved (less than 31 bytes).

MORE INFORMATION

================

For example, calling DdeCreateDataHandle() on a 3-byte buffer causes DDEML

to allocate a global memory block of 32 bytes and returns a data handle for

these 32 bytes of memory. If DdeGetData() or DdeAccessData() is used to

obtain the size of the data handle, then the return value will be 32 bytes

(or 28, depending on the type of transaction; please see NOTE below).

Similarly, if the data buffer was 35 bytes long, DdeCreateDataHandle()

allocates a global memory block of 64 bytes and returns the handle to that

memory block.

Internally, DDEML uses GlobalAlloc(GMEM_DDESHARE) to allocate global memory

and create data handles. GlobalAlloc() allocates memory from the global

heap and aligns the allocation size to a 32-byte boundary. Because the

function DdeCreateDataHandle() uses GlobalAlloc() to create data handles,

this overhead is imminent.

NOTE: For transactions such as XTYP_REQUEST, DDEML uses the first 4 bytes

of the data buffer for maintaining header information. Calling

DdeGetData(hData, NULL, 0, 0) to obtain the size of the memory object

associated with the data handle yields a return value of 28 bytes, instead

of the allocated 32 bytes. Transactions such as XTYP_EXECUTE, however, do

not use the first 4 bytes, so the return value is the full 32 bytes

allocated.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrDde


Top 10 DDEML Support Issues

Article ID: Q108933

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

---------------------------------------------------------------------

The following are the top 10 commonly asked DDEML issues:

 1. Q. The documentation for DdeCreateStringHandle() states that it applies

       to strings of any length. Why am I finding that strings are limited

       to 255 characters?

    A. Strings in DDEML are internally implemented as atoms, and as such,

       inherit the 255 character limit. This limit is maintained in 32-bit

       DDEML for backward compatibility.

       For more information, please see the following articles in the

       Microsoft Knowledge Base:

          ARTICLE-ID: Q102570

          TITLE     : DOCERR: DdeCreateStringHandle() lpszString param

 2. Q. Why is my call to DdeClientTransaction (..XTYP_EXECUTE,,) failing?

       I have specified a length of lstrlen (szBuffer).

    A. The documentation doesn't mention it, however, the buffer length

       specified should account for the null-terminating character, and

       therefore should be lstrlen(szBuffer) +1. You can verify this easily

       with DDESPY; watch garbage characters get appended to the command-

       string if an inadequate length is specified in the

       DdeClientTransaction() call.

       For additional information, please see the following article(s) in

       the Microsoft Knowledge Base:

          ARTICLE-ID: Q107387

          TITLE     : PRB: Inadequate Buffer Length Causes Strange Problems

                     in DDEML.

 3. Q. Is there a way for a client application to get to the result of an

       execute command it had sent a server application to execute?

       DdeClientTransaction()'s return value does not seem to help, nor

       does its lpuResult parameter contain anything relevant.

    A. You will have to establish your own protocol to do this. Either

       issue a separate XTYP_REQUEST for some item name (for example,

       ExecResult) after the XTYP_EXECUTE was sent, or set up an advise

       loop that immediately notifies the client of the execute result as

       soon as the command has executed.

       For additional information, please see the following article(s) in

       the Microsoft Knowledge Base:

          ARTICLE-ID: Q102574

          TITLE     : XTYP EXECUTE and its Return Value Limitations

 4. Q. When should a server application free data handles? How about a

       client application?

    A. Servers should free data handles when:

        - Created as HDATA_APPOWNED

        - The data handle is not passed to a client application

       For additional information, please see the following article(s) in

       the Microsoft Knowledge Base:

          ARTICLE-ID: Q83413

          TITLE     : Freeing Memory in a DDEML Server Application

       Clients should free data handles when:

        - Received synchronously as a return value from a call to

          DdeClientTransaction (..XTYP_REQUEST,,).

       For additional information, please see the following article(s) in

       the Microsoft Knowledge Base:

          ARTICLE-ID: Q83912

          TITLE     : Freeing Memory for Transactions in a DDEML

                      Client App

 5. Q. Why does my DdeInitialize() call fail when called from my dynamic-

       link library's (DLL's) LibMain() function? Calling it elsewhere in

       my DLL seems to work.

    A. DdeInitialize() causes windows to be created for DDEML's own use.

       This then causes messages to be sent to the calling application's

       message queue, which does not exist yet during LibMain() or

       DllMain() in an implicitly-loaded DLL. Moving the call to

       DdeInitialize() anywhere else in the DLL, or explicitly loading the

       DLL via LoadLibrary(), should fix the problem.

       For additional information, please see the following article(s) in

       the Microsoft Knowledge Base:

          ARTICLE-ID: Q94954

          TITLE     : PRB: DdeInitialize Fails in Implicitly-Loaded DLL's

                      LibMain()

 6. Q. How do I implement Paste Link in my client/server application?

    A. Client and Server applications that support the Paste Link command

       should register the "Link" clipboard format as shown:

          cfLink = RegisterClipboardFormat ("Link");

       When a user chooses Copy from a server application's Edit menu, the

       server copies to the clipboard a string in this format

          application\0topic\0item\0\0

       with a single null character separating the names, and two null

       characters terminating the string.

       When the user chooses Paste Link from a client's Edit menu, the

       client opens the clipboard and starts parsing the application,

       topic, and item names from the clipboard data. Using these names,

       it then attempts to establish a conversation on the

       application!topic, and sets up a hot advise loop on the item name.

       Refer to the Windows SDK version 3.1 SDK "Guide to Programming,"

       manual, Section 22.4.3.2, page 529.

 7. Q. I'm having a problem with the DdeCreateDataHandle() function; it

       does not seem to work as documented.

    A. The cbInitData param should be documented as specifying the amount

       of memory, in bytes, to copy from the source buffer pointed to by

       lpvSrcBuff.

       The offSrcBuf should have been documented as offTargetBuff, to point

       to the beginning of the global memory object (NOT the source buffer)

       where data is supposed to be copied.

 8. Q. I get a stack overflow when I call DdePostAdvise().

    A. You might be calling DdePostAdvise() from your DdeCallback, while

       processing the XTYP_ADVREQ transaction. This is the equivalent of

       calling InvalidateRect() from a window procedure's WM_PAINT case,

       which results in a similar stack overflow, because InvalidateRect()

       generates a WM_PAINT message.

       For additional information, please see the following articles in

       the Microsoft Knowledge Base:

          ARTICLE-ID: Q102571

          TITLE     : Calling DdePostAdvise() from XTYP ADVREQ

          -and-

          ARTICLE-ID: Q92540

          TITLE     : Is DdePostAdvise Synchronous?

 9. Q. 16-bit Windows only: When I call DdeCreateDataHandle() to allocate

       memory for a buffer 5-bytes long, why does

       DdeGetData(hData,NULL,0,0) return 32 bytes (or 28 bytes, depending

       on the transaction type) as the size of the memory block allocated?

    A. Internally, DDEML calls GlobalAlloc (GMEM_DDESHARE) to allocate

       global memory and create data handles. When GlobalAlloc() allocates

       memory, it aligns the allocation size to a 32 byte boundary, thus

       all memory allocations are done in multiples of 32 bytes.

       For more information, please see the following article in the

       Microsoft Knowledge Base:

          ARTICLE-ID: Q108926

          TITLE     : DdeCreateDataHandle Memory Allocation Granularity

                      DDEML

10. Q. How do I set up a conversation with Word/Excel and get either of

       them to execute commands?

    A. Call DdeConnect(), specifying "WinWord" and "System" or "Excel" and

       "System" as service and topic names respectively, and then send the

       command string to execute (in WordBasic command or Excel macro

       format respectively), enclosed in open and close brackets [].

       For example, to send WinWord a command to open a file, your call to

       DdeClientTransaction() should resemble the following:

          char szExecute[100];

          lstrcpy (szExecute,"[FileOpen(\"C:\\README.DOC\")]");

          DdeClientTransaction(lpszExecString, lstrlen (lpszExecString) +1,

                               hConvServer, NULL,

                               CF_TEXT, XTYP_EXECUTE,

                               1000, NULL);

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Graying Text in Disabled Multiline Edit Controls

Article ID: Q108937

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.10

---------------------------------------------------------------------

SUMMARY

=======

Disabling multiline edit controls prevents user input to the control, but

does not make the text unavailable (gray or dim) in the edit control.

However, single line edit controls, when disabled, make the text

unavailable, as well as preventing user input. This is a design feature in

Windows and is not a bug.

MORE INFORMATION

================

The rationale behind this design feature is that the single line edit

control is generally used in different circumstances than is the multiline

edit control. The single line edit control is used in such situations as

selecting a filename, where making the disabled text unavailable helps make

the user interface clearer. Multiline edit controls are often used as read-

only fields, and therefore need to be black when disabled.

One way to make the text of a disabled multiline edit control unavailable

is described below.

Whenever a predefined control is about to draw itself, it sends its parent

a WM_CTLCOLOR message. The parent can use this message to set the control's

text and background colors.

In the window procedure of the multiline edit control's parent window,

process the WM_CTLCOLOR message as follows:

Sample Code

-----------

 static HBRUS  hBrush;

 case WM_INITDIALOG:

   hBrush = CreateSolidBrush (GetSysColor (COLOR_WINDOW));

   break;

 case WM_CTLCOLOR:

   /* If the control is disabled, set the text color to gray and the

    * background color to the system window background color.

    */

    hCtl = GetDlgItem (hDlg, IDC_MULTIEDIT );

    enabled = IsWindowEnabled(hCtl) ;

    if ((!enabled) && (HIWORD(lParam) == CTLCOLOR_EDIT)) {

      SetTextColor(wParam, RGB(128,128,128) );

      SetBkColor( wParam, GetSysColor (COLOR_WINDOW));

      return ((HBRUSH) hBrush);

    }

    break;

  InvalidateRect (hCtl, NULL, TRUE);

  UpdateWindow (hCtl);

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: UsrCtl


PRB: Windows 3.1 SDK HOOKS Sample Causes a GP Fault

Article ID: Q110661

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

An application that installs a WH_CBT hook function that is run along with

the HOOKS sample application will cause a general protection (GP) fault in

the system if the computer-based training (CBT) hook is enabled and the

hook procedure receives a CBT notification.

CAUSE

=====

In the HOOKS sample, CBTFunc() is incorrectly casting lParam (a DWORD

value) to a WORD when it calls CallNextHookEx() to pass the info on to the

next hook in the hook chain. This causes the receiving hook function to

receive the CBT notification with a modified lParam (the HIWORD stripped

off), thus translating to an invalid pointer and eventually causing a GP

fault.

A GP fault occurs similarly when an application that installs a

WH_CALLWNDPROC hook is run along with the HOOKS sample and the CallWndProc

hook menu-item is selected. In the same manner, the HOOKS sample function

CallWndProcFunc() incorrectly casts its lParam (a DWORD value) to a WORD on

its call to CallNextHookEx().

In addition, the HOOKs sample will GP Fault when the WH_JOURNALRECORD hook

is installed and some other application calls SetSysModalWindow(). As

mentioned in the Windows 3.1 SDK help,

   If a WH_JOURNALRECORD hook is in place when SetSysModalWindow is called,

   the hook is called with a hook code of HC_SYSMODALON (for turning on the

   system-modal window) or HC_SYSMODALOFF (for turning off the system-modal

   window).

RESOLUTION

==========

Modify both the CBTFunc() and CallWndProcFunc() calls to CallNextHookEx()

to correctly cast lParam to a DWORD.

In the case of the journal record hook, make the following change to the

function JournalRecordFunc in hooksdll.c:

   if( nCode >= 0) {

   // do not  record if SysModalOn or SysModalOff and let other filter know

   // about it.

      if(nCode == HC_SYSMODALON || nCode == HC_SYSMODALOFF)

      {

      // let other hook filters know about this

         CallNextHookEx(hhookHooks[JOURNALRECORDINDEX], nCode, wParam,

            lParam);

         return;

      }

Additional reference words: 3.10 gpf gp-fault

KBCategory: kbprg kbprb

KBSubcategory: UsrHks


PRB: GetVersion Returns 3.10 from Windows for Workgroups 3.11

Article ID: Q113892

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Windows SDK for Windows for Workgroups version 3.11

----------------------------------------------------------------------

SYMPTOMS

========

GetVersion() returns 3.10 when running under Windows for Workgroups version

3.11.

CAUSE

=====

GetVersion() still returns 3.10 from Windows for Workgroups version 3.11

because there are too many applications that are checking for version 3.10.

GetVersion() returns 3.10 to maintain compatibility with those applications

that check for Windows version 3.10.

RESOLUTION

==========

Windows applications that use the C language can use the following set of

functions to get the actual version information.

  GetFileVersionInfoSize("user.exe"...);

  GetFileVersionInfo("user.exe"...);

  VerQueryValue(...);

For a complete sample application that does this, please see the sample in

the ..\SAMPLES\VERSTAMP directory from Microsoft Visual C++.

Below is a Visual Basic program that uses the GetFileVersionInfo() function

to get the actual version information.

   Declare Function GetFileVersionInfo% Lib "ver.dll"

      (ByVal lpszFileName$, ByVal handle As Any, ByVal

       cbBuf&, ByVal lpvData$)

     Dim pos As Integer

     Dim version As String * 255

     Dim ans As String

     ' get the version info and fill the version string

     ret% = GetFileVersionInfo("user.exe", 0&, 254, version)

     ' find the position in the string where the FileVersion stamp is.

     pos = InStr(1, version, "FileVersion")

     ' 12 = lengh of "FileVersion" +1 for the null

     ' 4  = length of string to return i.e. "3.11"

     ans = Mid$(version, pos + 12, 4)

     ' display answer

     MsgBox ans

Additional reference words: 3.00 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrSys


PRB: Caret Appears Outside Border in Multiline Edit Control

Article ID: Q127153

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

If a multiline edit control is created with the WS_HSCROLL and ES_MULTILINE

style, the caret may still be visible even when it is scrolled beyond the

area of the edit control. For example, if a line is longer than the edit

control and the caret is placed at the start of the line, when the the edit

is scrolled toward the end of the line, the caret becomes visible outside

of the control.

CAUSE

=====

The CS_PARENTDC class style is on the standard edit control to allow

Windows version 3.1 edit controls to be compatible with Windows version 3.0

edit controls. This causes this behavior.

RESOLUTION

==========

To avoid this behavior:

 - Give the parent window of the edit control the WS_CLIPCHILDREN style.

   -or-

 - Use a superclass of the edit control with a class style of CS_DBLCLKS.

   This is different from the standard edit control, which has both the

   CS_DBLCLKS and CS_PARENTDC class styles set.

NOTE: Neither Windows NT version 3.5 nor Windows 95 exhibit this behavior.

Additional reference words: 3.10

KBCategory: kbui kbprb

KBSubcategory: UsrCtl


BUG: No WM_SETFONT to Custom Controls

Article ID: Q70818

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0

----------------------------------------------------------------------

SYMPTOMS

========

In the Dialog Editor, when the font of the dialog box is changed, the

text of custom controls that process WM_SETFONT messages does not

change.

CAUSE

=====

The Dialog Editor does not send WM_SETFONT messages to custom

controls.

STATUS

======

Microsoft has confirmed this to be a bug in the Windows SDK version 3.0. We

are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 3.00

KBCategory: kbtool kbbuglist

KBSubcategory: TlsDlg


BUG: RC Error RW1008 If NULL Entry in PATH

Article ID: Q71022

------------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

------------------------------------------------------------------------

SYMPTOMS

========

The resource compiler (RC) exits with the message "fatal error RW1008:

RCPP.ERR not found."

CAUSE

=====

There is a NULL entry in the MS-DOS PATH environment variable (for

example: SET PATH=;c:\;...).

STATUS

======

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article.We are researching this bug and will post

new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 3.00 3.10

KBCategory: kbtool kbbuglist

KBSubcategory: TlsRc


BUG: Complex Graphics Image Partially Printed

Article ID: Q72493

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application uses the clipping functions to print a complex graphics

image on a high resolution output device, the printed output is incomplete;

portions of the image are missing.

CAUSE

=====

The clipping region is stored in the graphics device interface (GDI) local

heap. It is possible for the local heap to run out of memory.

RESOLUTION

==========

Some of the clipping must be done by the application to reduce the amount

of GDI local heap used.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: FatalExit() Interacts Through Terminal Only

Article ID: Q72497

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Under the debugging version of Windows, when a debugger is not in use

and the FatalExit() function interacts with the user, the interaction

is through a terminal connected to the AUX port and not through the

console keyboard and a secondary monitor if one is installed.

RESOLUTION

==========

In versions of Windows earlier than version 3.0, and in Windows 3.0 real

mode, the device driver OS.SYS can be installed to redirect information

form FatalExit () to a secondary monitor and the console keyboard. Under

Windows 3.0 standard and enhanced modes and under Windows 3.1 OX.SYS will

only redirect output and the console keyboard will not be redirected. After

a FatalExit () call has occured, the computer must be rebooted to regain

control.

STATUS

======

Microsoft has confirmed this to be a limitation of the Windows SDK

versions 3.0 and 3.1. We are researching this problem and will post new

information here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrInp


BUG: MapVirtualKey() Maps Keypad Keys Incorrectly

Article ID: Q72583

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When MapVirtualKey() is passed valid virtual key codes for the keys on

the numeric keypad, invalid scan codes and ASCII codes are returned.

CAUSE

=====

The Windows keyboard driver does not map all valid virtual keys to

their scan codes and ASCII equivalents.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.0.

We are researching this problem and will post new information here as

it becomes available.

Additional reference words: buglist3.00 3.00

KBCategory: kbprg kbbuglist

KBSubcategory: UsrInp


BUG: Crash with frexp() in Small or Medium Model DLL

Article ID: Q73184

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Although the C Run-time function frexp() is included in the Windows version

libraries for dynamic-link libraries (DLLs), when it is called from a

Windows small model or medium model DLL, the application crashes.

STATUS

======

Microsoft has confirmed this to be a bug in the DLL libraries for

Windows version 3.0 and 3.1. We are researching this problem and will post

new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrDll


BUG: Combo Boxes in DS_SYSMODAL Dialog Boxes

Article ID: Q74507

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style is used

inside a system modal dialog box, it causes the following problem in

Windows versions 3.0 and 3.1:

1. An item cannot be selected from the drop-down list box by

   clicking it with the mouse. The original selection remains in

   the edit control or static-text control.

Using a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style within a

system modal dialog box in Windows version 3.0 causes the following

problems:

1. The drop-down list box cannot be closed by clicking on a part of

   the list box that lies outside the dialog box.

2. The parts of the drop-down list box that lie outside the dialog

   box are not erased when the drop-down list box is closed.

CAUSE

=====

The mouse messages meant for the drop-down list box never reach the list

box.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We will post new information here in the Knowledge Base when it

becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10 combobox

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: PostScript Driver Version 3.4 Returns Incorrect Page Size

Article ID: Q76364

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

In version 3.4 of the PostScript printer driver, when the DC_PAPERSIZE

index is specified in the DeviceCapabilities function, the width of the

paper is returned for both the x and y coordinates in each POINT structure.

This function should return the height and width of each supported paper

size.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and 3.1,

and in version 3.4 of the PostScript driver. We are researching this

problem and will post new information here as it becomes available.

Additional reference words: 3.00 3.10 buglist3.00 buglist3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: Protected-Mode GlobalCompact() Return Not Free Memory

Article ID: Q76686

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SYMPTOMS

========

When Windows is running in one of its protected modes, the value returned

by the GlobalCompact() API does not accurately reflect the amount of free

memory available in the system.

In enhanced mode, Windows can swap memory objects to disk. This process

takes a long time relative to accessing an object in memory. Therefore,

GlobalCompact() returns the amount of memory available without performing

any paging.

In standard mode, GlobalCompact() never reports more than 1 megabyte (MB)

of memory free because of a memory allocation limit on the 80286 chip.

STATUS

======

Microsoft has confirmed that this problem occurs in Windows versions 3.0

and 3.1. We are researching this problem and will post new information here

as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrMm


BUG: Text Formatting Lost When Edit Text Dialog Box Used

Article ID: Q80143

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SYMPTOMS

========

When the Edit Text dialog box is used to edit formatted text in an

application developed for Microsoft Windows for Pen Computing, formatting

is lost.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows for Pen

Computing version 1.0. We are researching this problem and will post new

information here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: 1.00 buglist1.00

KBCategory: kbprg kbbuglist

KBSubcategory: WpenMisc


BUG: Common Dialog GP-Fault on ESC Key with Mouse Button Down

Article ID: Q83009

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In an application that uses the File Open or Save As dialog box from the

Common Dialogs dynamic-link library (DLL), when the user opens a combo box

with the mouse, holds down the left mouse button, and then presses the ESC

key to close the dialog box, a GP-fault occurs.

RESOLUTION

==========

You can ignore the faults that result from calling GetOpenFileName() and

GetSaveFileName() without incident. There are as many as eight warnings

before control is returned to the application.

STATUS

======

Microsoft has confirmed this to be a bug in the Common Dialogs DLL

version 3.1. We are researching this problem and will post new information

here as it becomes available.

Additional reference words: 3.10 buglist3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCmnDlg


BUG: GlobalPageLock() Moves Memory Fixed by GlobalFix()

Article ID: Q85329

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application calls the GlobalPageLock() function specifying the

handle to a block of memory that has been fixed in place by the GlobalFix()

function, the address of the memory block can change.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The following steps demonstrate this problem:

1. Allocate a block of movable memory using the GlobalAlloc() function.

2. Fix the address of the memory block using the GlobalFix() function.

3. Increment the memory block's page-lock count using the

   GlobalPageLock() function.

The address of the memory block should not change between step 2 and step 3

above.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrMm


BUG: GetModuleFileName() Returns Relative File Path

Article ID: Q85330

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the GetModuleFileName() function returns a reference to a dynamic-link

library (DLL) file, the reference is relative (not fully qualified) under

the following circumstances:

 - One of the directory references in the MS-DOS PATH environment variable

   is relative. Assume that the relative directory reference refers to

   drive X.

 - An application is implicitly linked to a DLL. The DLL is installed in

   the current (default) directory of drive X.

 - The application is installed in a directory other than the one in which

   the DLL is installed.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The following describes the situations under which this problem occurs:

 - The PATH statement in the AUTOEXEC.BAT file resembles the following:

      PATH=C:\DOS;C:\WINDOWS;D:.;C:\APPS

   The relative reference in this path refers to drive D.

 - Run an application from the C:\WINDOWS directory that implicitly links

   to a DLL that is stored in the current (default) directory of the D

   drive.

 - If any application calls the GetModuleFileName() to retrieve the file

   name for the DLL, the function returns a relative reference to the file

   (for example, D:.\DLL.DLL).

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrTsksIns


BUG: System Menu Wrong for CS_NOCLOSE-Style MDI Child

Article ID: Q85331

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application registers a window class with the CS_NOCLOSE style and

creates a multiple document interface (MDI) child window using the class,

the menu items in the child window's system menu are incorrect.

Specifically, the Switch To option appears where the Next option belongs.

Choosing Switch To activates the Windows Task Manager.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrMdi


BUG: Buttons Painted Incorrectly After Color Changed

Article ID: Q85593

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the Colors application in the Control Panel is used to change the

button shadow color to white, all push button windows are painted

incorrectly. Specifically, the Button Shadow and Button Highlight colors

are not painted at all.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: SETCOLORTABLE Escape Disables Dithering

Article ID: Q85596

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When the VGAPAL video driver is installed on a system, once an application

calls the SETCOLORTABLE escape to change an entry in the color table

associated with a device context, Windows does not create any dithered

brushes for that device context. Instead, Windows returns the solid brush

that most closely matches the requested color.

RESOLUTION

==========

To work around this problem, reset the color table to its original state by

specifying NULL as the value of the lpInData and lpOutData parameters in a

call to the SETCOLORTABLE escape, as follows:

   Escape(hDC, SETCOLORTABLE, 0, NULL, NULL)

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The SETCOLORTABLE escape is documented on pages 500 and 501 of the

"Microsoft Software Development Kit: Programmer's Reference, Volume 3:

Messages, Structures and Macros" manual.

The comments regarding this escape state the following:

 - The color-mapping algorithms in the display driver will most likely

   not work with a changed palette.

 - If the color index pointed to by the lpInData parameter is 0xFFFF,

   the calling application performs all color mapping.

 - Once an application restores the color table to its original state,

   an application can enable the color-mapping algorithms in the

   display driver.

However, with the VGAPAL driver, calling the SETCOLORTABLE escape with

lpInData pointing to the 0xFFFE value does not restore dithering.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPal


BUG: GetGlyphOutline() Returns Blank Bitmap

Article ID: Q85598

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows graphical environment, when an application calls

the GetGlyphOutline() function to retrieve the bitmap for a glyph and the

lpmat2 parameter points to a matrix that magnifies the glyph, a blank

bitmap is returned.

RESOLUTION

==========

Specify the desired glyph size in the lfHeight member of the LOGFONT data

structure used to create the font. Do not magnify the glyph with the matrix

specified in the lpmat2 parameter.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiTt


BUG: Input Focus Lost When Control Returns From Windows Help

Article ID: Q85896

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application calls the WinHelp function and specifies

HELP_CONTEXTPOPUP as the value for the fuCommand parameter, the

input focus disappears. When the user presses the ALT key, the

system menu appears for a hidden copy of the Windows Help

application.

CAUSE

=====

The Windows Help application does not properly restore the focus to

the calling application when the pop-up window is destroyed.

STATUS

======

Microsoft has confirmed this to be a bug with Windows Help

version 3.1. We are researching this problem and will post new

information here as it becomes available.

Additional reference words: 3.10 buglist3.10

KBCategory: kbtool kbprg kbbuglist

KBSubcategory: UsrInp


BUG: LIBENTRY.ASM Missing Include File Error

Article ID: Q86409

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

An attempt to assemble the LIBENTRY.ASM file distributed with version 3.1

of the Microsoft Windows SDK fails with the following message:

   Include file not found: CONVDLL.INC.

CAUSE

=====

CONVDLL.INC is an assembly-language include file required to support the

Microsoft Windows Libraries for OS/2 (WLO). Because CONVDLL.INC is not

required to create Windows dynamic-link libraries (DLLs), it is not

included in the Windows SDK.

RESOLUTION

==========

Modify the LIBENTRY.ASM file to remove or comment out the following line

from the file:

   INCLUDE CONVDLL.INC

STATUS

======

Microsoft has confirmed this to be a problem with the LIBENTRY.ASM file

included in version 3.1 of the Microsoft Windows SDK. We will post new

information here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbtool kbbuglist

KBSubcategory: TlsMisc


BUG: MDI More Windows Dialog Activates Wrong Child

Article ID: Q86412

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In a multiple document interface (MDI) application developed for Microsoft

Windows version 3.1, when the application creates more than nine MDI child

windows, the user chooses More Windows from the Window menu, and selects an

MDI child window to activate from the list displayed in the Select Window

dialog box, the application activates a different window.

CAUSE

=====

When one or more MDI child windows are hidden by an application, the

default frame window procedure (DefFrameProc) activates the wrong window.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrMdi


BUG: PrintForm() Does Not Print Ink from Control

Article ID: Q86874

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SYMPTOMS

========

When an application developed using the Visual Basic controls provided in

version 1.0 of Microsoft Windows for Pen Computing calls the Visual Basic

PrintForm() function, ink entered into the control does not print.

CAUSE

=====

The control is set for delayed recognition. The Visual Basic controls

provided with version 1.0 of Windows for Pen Computing do not support

printing ink when the control is in delayed recognition mode.

RESOLUTION

==========

To work around this problem, modify the application to remove delayed

recognition mode.

STATUS

======

Microsoft has confirmed this to be a bug in Windows for Pen Computing

version 1.0. We are researching this problem and will post new information

here as it becomes available.

Additional reference words: buglist1.00 1.00

KBCategory: kbprg kbbuglist

KBSubcategory: WpenVB


BUG: Dsklayt2 /W Option Without Disk Number Fails

Article ID: Q86875

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Specifying the /W option switch to the Dsklayt2 program displays

the program's usage screen.

CAUSE

=====

Unless a number immediately follows the /W option switch, the /W

option switch is not allowed.

STATUS

======

Microsoft has confirmed this to be a problem in the Dsklayt2

program in the Microsoft Windows Software Development Kit (SDK)

version 3.1. We are researching this problem and will post new

information here as it becomes available.

MORE INFORMATION

================

Beginning on page 42 of the "Microsoft Windows Software Development

Kit: Setup Toolkit for Windows," the /W option switch is documented as

follows:

   Specifies the writable disk. For n, specify a disk number. This

   field overrides the specification in the layout file. If you omit

   this option, Dsklayt2 makes the last disk in the installation the

   writable disk. If you specify the option without a disk number,

   Dsklayt2 assumes that all disks are read-only.

The /W option is not required to build a set of installation disks. If

you do not specify the /W option, Dsklayt2 creates a setup information

(INF) file that labels the last disk in the layout as a writable disk.

If the setup script does not specify a label for the final disk, when

the user runs the setup script, Setup will request the final disk as

the "writable" disk. To avoid this situation, specify a label for each

disk.

The Dsklayt2 program works in conjunction with the Dsklayt program.

The /W option switch invokes the Writable Label feature in the Dsklayt

program. Chapter 4 of the "Setup Toolkit" manual documents both

programs as part of the Disk Layout Utilities.

Additional reference words: 3.10 docerr

KBCategory: kbtool kbprg kbdocerr kbbuglist

KBSubcategory: TlsMss


BUG: Dictionary Receives No DIRQ_SYMBOLGRAPH Message

Article ID: Q87006

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SYMPTOMS

========

In an application developed for Microsoft Windows for Pen Computing, the

dictionary function does not receive a DIRQ_SYMBOLGRAPH message for a given

recognition session.

CAUSE

=====

Windows for Pen Computing detected an unrecognized symbol in the symbol

graph.

STATUS

======

Microsoft has confirmed this to be a bug in Windows for Pen Computing

version 1.0. We are researching this problem and will post new information

here as it becomes available.

MORE INFORMATION

================

In the Windows for Pen Computing environment, a dictionary can be designed

to process the DIRQ_SYMBOLGRAPH message. If an application specifies the

RCO_SUGGEST flag in the lRcOption member of the recognition context (RC)

data structure, Windows for Pen Computing sends this message to a

dictionary before any other message. If an application also specifies the

RCO_NOSPACEBREAK flag, the system sends the complete symbol graph to the

dictionary. Unfortunately, Windows for Pen Computing scans the symbol graph

for any SYV_UNKNOWN symbols before the system sends the DIRQ_SYMBOLGRAPH

message to the dictionary. If the symbol graph contains a SYV_UNKNOWN

symbol, no DIRQ_SYMBOLGRAPH message is sent.

Additional reference words: buglist1.00 1.00

KBCategory: kbprg kbbuglist

KBSubcategory: WpenDict


BUG: Help Compiler Hangs When .HPJ File [MAP] Section Too Big

Article ID: Q87007

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Compiling a help project (HPJ) file with the Microsoft Windows Help

Compiler causes the system to hang, reboot, or cause a system integrity

violation.

CAUSE

=====

The [MAP] section of the HPJ file contains more than approximately 4096

entries.

STATUS

======

Microsoft has confirmed this to be a bug in version 3.1 of the Windows

Help Compiler provided with the Microsoft Windows SDK version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 HC31 HC31.EXE HCP HCP.EXE

KBCategory: kbtool kbbuglist

KBSubcategory: TlsHlp


BUG: OpenFile() API Fails on Novell Temp Drive

Article ID: Q87347

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows graphical environment, when an application uses

the OpenFile() API to open a file on a Novell network temporary drive, the

function returns the value HFILE_ERROR to indicate failure.

CAUSE

=====

The OpenFile() function does not properly parse the nonalphabetic

characters that the Novell network redirector uses to represent temporary

drive mappings.

RESOLUTION

==========

To work around this problem, use the _lopen() function to obtain a file

handle.

STATUS

======

Microsoft has confirmed this to be a problem with Windows version 3.1. We

are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrFileIO


BUG: HPPCL Driver Reports SETABORTPROC Not Supported

Article ID: Q87348

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application for the Microsoft Windows environment sends the

QUERYESCSUPPORT printer escape to the Hewlett-Packard (HP) LaserJet (HPPCL)

printer driver to determine whether the SETABORTPROC escape is supported,

the Escape function returns the value 0 (zero), indicating that the escape

is not supported. However, an application can successfully send the

SETABORTPROC escape to the HPPCL printer driver.

STATUS

======

Microsoft has confirmed this to be a problem with version 31.3.89 of the

HPPCL printer driver distributed with Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: Color PostScript Drivers Report Incorrect Data

Article ID: Q87349

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows graphical environment, when an application creates

a printer device context (DC) for a QMS ColorScript 100 printer or for a

Seiko ColorPoint PS printer, and specifies the DC in a call to the

GetDeviceCaps() function, each driver reports the following information

about itself:

   BITSPIXEL  = 1

   PLANES     = 1

   NUMCOLORS  = 8

At least one of these numbers is incorrect in each case.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: GetGlyphOutline() Returns Partial Glyph

Article ID: Q87350

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows graphical environment, when an application calls

the GetGlyphOutline function to retrieve the bitmap for a rotated glyph

(the lpmat2 matrix points to a nonidentity rotation matrix) and the glyph

is larger than 75 pixels, the returned bitmap contains a partial,

nonrotated, glyph.

RESOLUTION

==========

To work around this problem, perform the following five steps:

1. Select the font into an appropriate device context (DC).

2. Determine the size of the bitmap required to hold the rotated glyph by

   performing the following three steps:

   a. Call the GetCharABCWidths() function to determine the (nonrotated)

      width of the black part of glyph. This information is returned in the

      abcB member of an ABC data structure.

   b. Call the GetTextMetrics() function to fill a TEXTMETRICS data

      structure with information about the font. Use the value of the

      tmHeight member of the TEXTMETRICS structure as the height.

   c. Use the angle of rotation to compute the width and height of the

      rotated glyph based on the information above.

3. Create a bitmap of the size calculated in step 2 and select it into a

   memory DC.

4. Create a rotated version of the font by specifying the rotation angle

   in the lfOrientation member of the LOGFONT data structure and select it

   into the memory DC.

5. Call the TextOut() function to write the desired glyph into the memory

   DC.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiTt


BUG: Scrolling DIB DC Fails

Article ID: Q87351

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application developed for version 3.1 of the Microsoft Windows

graphical environment uses the BitBlt() or ScrollDC() functions to scroll a

device context created using the DIB (device-independent bitmap) driver,

the process fails with a variety of symptoms including a general protection

(GP) fault, a page fault, or random data appearing in the DIB.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 gpf gp-fault

KBCategory: kbprg kbbuglist

KBSubcategory: GdiBmp


BUG: Setup CreateProgmanItem Does Not Overwrite Item

Article ID: Q87493

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Setup Toolkit for Windows, when the setup script calls the

CreateProgmanItem() subroutine to replace an existing item in a Microsoft

Windows Program Manager group with cmo% set to cmoOverwrite and with

szOther$ set to a nonempty string, the setup driver does not replace the

existing item. Instead, it creates a new item.

CAUSE

=====

_MSTEST, the setup driver spawned by SETUP.EXE, incorrectly forms the name

of the item to overwrite if szOther$ is not an empty string. This prevents

_MSTEST from finding an item in the group with the specified name, and it

creates a new item.

RESOLUTION

==========

Microsoft has confirmed this to be a bug in version 3.1 of the Setup

Toolkit for Windows. If the setup script must specify the icon file, icon

resource index, x and y icon position, or working directory, and if it is

unacceptable to potentially have two items of the same name in a group, the

groups must be manipulated through a dynamic data exchange (DDE)

conversation with Program Manager. Add a function that initiates and

manages a DDE conversation with Program Manager to MCUISTF.DLL and call the

function from the setup script.

MORE INFORMATION

================

Windows 3.0 does not support the cmoOverwrite command option flag for the

CreateProgmanItem() subroutine.

Additional reference words: buglist3.10 3.10 MSSetup tool kit

KBCategory: kbtool kbbuglist

KBSubcategory: TlsMss


BUG: BitBlt() Bitmap on VGA Display Causes GP Fault

Article ID: Q87494

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When an application for the Microsoft Windows environment calls BitBlt()

to copy a large (640 x 480) bitmap to the VGA screen, the application

experiences a general protection (GP) fault.

RESOLUTION

==========

Increase the size of the bitmap to store one additional scan line. Use the

BitBlt function to copy only the desired portion of the bitmap to the

screen.

STATUS

======

Microsoft has confirmed this to be a problem with Windows version 3.1. We

are researching this problem and will post more information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

There are two methods for increasing the size of the bitmap. If the

contents of the bitmap are fixed, Microsoft Paintbrush or a similar image-

editing tool can be used to add or remove a scanline from the bitmap.

If the image changes, the following eight steps add a scanline to a bitmap

under program control and copy the bitmap to the screen. The handle to the

original bitmap is stored in the hBMPOriginal variable.

1. Declare variables.

      HBITMAP hBMPCompatible, hBMPOld1, hBMPOld2;

      HDC hDCMem1, hDCMem2, HDCScreen;

2. Retrieve a display context (DC) for the screen.

      hDCScreen = GetDC(NULL);

3. Create a bitmap compatible with the screen that contains one more

   scanline than the original bitmap.

      hBMPCompatible = CreateCompatibleBitmap(hDCScreen, 640, 481);

4. Create two memory DCs compatible with the screen.

      hDCMem1 = CreateCompatibleDC(hDCScreen);

      hDCMem2 = CreateCompatibleDC(hDCScreen);

5. Select the original bitmap into one of the DCs. Select the new bitmap

   into the other.

      hBMPOld1 = SelectObject(hDCMem1, hBMPOriginal);

      hBMPOld2 = SelectObject(hDCMem2, hBMPCompatible);

6. Use the BitBlt function to copy the original bitmap into the compatible

   bitmap. The function does not fill the bottom scanline because the

   bottom scanline is not copied to the screen.

      BitBlt(hDCMem2, 0, 0, 640, 480, hDCMem1, 0, 0, SRCCOPY);

7. Copy the compatible bitmap to the screen.

      BitBlt(hDCScreen, 0, 0, 640, 480, hDCMem2, 0, 0, SRCCOPY);

8. Free resources. Note that the code below deletes the compatible bitmap.

   If the bitmap is required later in the program, defer deleting the

   bitmap until just before the application closes.

      hBMPCompatible = SelectObject(hDCMem2, hBMPOld2);

      DeleteObject(hBMPCompatible);

      hBMPOriginal = SelectObject(hDCMem1, hBMPOld1);

      DeleteDC(hDCMem1);

      DeleteDC(hDCMem2);

      ReleaseDC(NULL, hDCScreen);

Additional reference words: buglist3.10 3.10 scan line

KBCategory: kbprg kbbuglist

KBSubcategory: GdiBmp


BUG: HC Error 2050 from #include in Help Project File (.HPJ)

Article ID: Q88126

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When you are building a Help file with the Microsoft Windows Help Compiler,

the process stops with the following error message:

   Error 2050: line <number> of <filename>.HPJ : Invalid #include

   syntax

CAUSE

=====

The Help project (.HPJ) file contains a #include statement where the

filename is delimited by quotation marks ("") rather than angle brackets

(<>).

RESOLUTION

==========

To work around this problem, modify the .HPJ file to delimit the filename

in the #include statement with angle brackets. For example, replace the

following statement

   #include "map.h"

with the following:

   #include <map.h>

STATUS

======

Microsoft has confirmed this to be a problem with the Windows Help Compiler

version 3.1. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 HC31 HC31.EXE HCP HCP.EXE

KBCategory: kbtool kbbuglist

KBSubcategory: TlsHlp


BUG: No Dr. Watson Log File in Drive's Root Directory

Article ID: Q88127

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows operating system, when the Dr. Watson fault-

logging application is installed and an application execution error occurs,

the Dr. Watson's Clues dialog box does not appear. Opening the Dr. Watson

application reveals that an error exists in the <logical

drive>:\\DRWATSON.LOG file.

CAUSE

=====

The Windows directory is the root directory of a logical drive, and the

logical drive is listed in the MS-DOS PATH environment variable in the

AUTOEXEC.BAT file.

RESOLUTION

==========

To work around this problem, do not map the Windows directory to the root

directory of a logical drive.

STATUS

======

Microsoft has confirmed this to be a problem with Dr. Watson version 3.1,

which is provided with Windows version 3.1. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbtool kbbuglist

KBSubcategory: TlsDrWatson


BUG: Minimized Windows Help Yields Incorrect Icon

Article ID: Q88128

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In a Microsoft Windows Help file, when a topic is displayed in a secondary

window, the icon specified in the ICON statement in the [OPTIONS] section

of the Help project (.HPJ) file does not appear when the user minimizes the

Help application. This condition persists even after the user closes the

secondary window.

CAUSE

=====

The topic in the secondary window is stored in a separate Help file. The

icon from this file displaces the icon for the main Help file.

RESOLUTION

==========

To work around this problem, modify the ICON statement in the [OPTIONS]

section of the .HPJ file that contains the topic for the secondary window

to specify the same icon as the main Help file.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows Help

version 3.1. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 WinHelp HC31 HC31.EXE HCP

HCP.EXE

ICON=icon-file

KBCategory: kbtool kbbuglist

KBSubcategory: TlsHlp


BUG: Complex Clipping Region Might Cause UAE/GP Fault

Article ID: Q89641

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Drawing lines to a memory DC containing a complex clipping region causes an

unrecoverable application error (UAE) or general protection (GP) fault.

CAUSE

=====

Under certain rare conditions, drawing a single line to a DC containing a

complex clipping region will cause a UAE under Windows 3.0 and a GP fault

under Windows 3.1.

The conditions for this UAE/GP fault to occur are as follows:

 - The clipping region for the DC must be a complex region. For example,

   the clipping region must contain multiple rectangles. [The

   ExcludeClipRect() and IntersectClipRect() functions will also tell you

   whether the region is complex.]

 - The clipping region must have its top physical coordinate at the Y

   origin. For example, if you are using a memory bitmap in the MM_TEXT

   mapping mode, the clipping region might have an upper-left corner of

   (0,0).

 - The line being drawn must be a "Y-major" line, meaning that the line

   extends in the Y-direction farther than it does in the X- direction.

 - The line must start above the top edge of the region (negative Y space)

   and end 1 pixel from the upper-right corner of the clipping region.

For the UAE/GP fault to occur, all the above conditions must be met.

For example, when the following GDI calls are performed on a memory

bitmap, a UAE/GP fault will occur in the VGA display driver:

   IntersectClipRect(hDC, 0, 0, 20, 20); // Top is at Y=0

   ExcludeClipRect(hDC, 5, 5, 15, 30);   // Makes region complex

   MoveTo(hDC, 15,-10);            // This line is Y-major

   LineTo(hDC, 19, 0);             // Hits upper-right of region

The UAE/GP fault occurs at the display driver level because GDI is sending

an incorrect parameter to the display driver's Output() function. The

clipping rectangle sent to this function contains a -1 for one of the

points, and negative values for clipping rectangles are not valid. A few

display drivers, for example the XGA driver, perform parameter checking on

this clipping rectangle and will not fail. Others, like the V7VGA, VGA, and

8514/a display drivers do not perform validation on this call and will

produce a UAE/GP fault.

RESOLUTION

==========

Because this problem occurs only when the Y origin of your hDC is at the

physical (screen coordinate) Y origin, it is unlikely that this problem

will occur while you are drawing to a standard screen DC. For this UAE/GP

fault to occur on a screen DC, the top of your client area would have to be

at the screen Y origin, which is normally not the case.

On the other hand, memory bitmaps are implemented so that the physical Y

origin is at the top of the bitmap, and the UAE/GP fault is much more

likely to occur when drawing to a memory bitmap. If your application uses

complex clipping regions on a memory DC, do the following to work around

this problem:

1. Assuming you're working in the MM_TEXT mapping mode, set your Viewport

   origin to (0,-1) by calling SetViewportOrg(hMemDC, 0,- 1). This will

   cause your logical origin (0,0) to be moved one pixel down in the DC.

2. Make sure that your logical clipping rectangle does not extend above the

   logical Y=0 origin. In other words, the top Y coordinate of your

   clipping rectangle cannot be less than 0 (or less than 1).

To ensure that the second condition is met, you must verify that all calls

to IntersectClipRect() and ExcludeClipRect() (which both take logical

coordinates) do not cause a logical clipping region that extends above the

Y origin to be created.

Note that there is a distinction between logical and physical clipping

regions; the above workaround works only with a logical clipping region. If

you create a region and then select it into your DC as a clipping region,

the coordinates for this region are device coordinates rather than logical

coordinates. In this case, you need to manually offset of the top of the

region by 1.

Some of the functions that create physical regions are CreateRectRgn(),

CreateEllipticRgn(), and OffsetRgn(). The functions GetClipBox() and

GetRgnBox() can be used to determine the upper physical-coordinate extent

of the regions.

If your application uses only the functions IntersectClipRect() and

ExcludeClipRect(), your clipping regions will be in logical units.

Another workaround is to either not use complex clipping regions in your

memory bitmaps or manually verify that no lines will be drawn above the top

of your Y origin.

NOTE: This UAE/GP fault might be generated for more than just

MoveTo()/LineTo() calls--it can occur for any GDI call that generates

lines, including rectangle, polygon, polypolygon, arc, and vector font

output.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0, 3.0a,

and 3.1. However, because the conditions for this error to occur are very

specific, most Windows applications will never encounter this problem. We

are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: 3.00 3.00a 3.10 OS_POLYLINE buglist3.00

buglist3.00a buglist3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDc


BUG: Cannot Map TT Font to Same Name PostScript Device Font

Article ID: Q92411

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

If a TrueType (TT) font and a PostScript (PS) printer font have the same

name, the TT font cannot be mapped to a different printer font. The mapping

works correctly for TT fonts whose names are different than the fonts on

the printer.

For example, the TrueType Symbol font can be mapped only to the Symbol font

resident on the PostScript printer.

STATUS

======

Microsoft has confirmed this to be a problem. We are researching this

problem and will post new information here in the Microsoft Knowledge Base

as it becomes available.

MORE INFORMATION

================

To reproduce this problem, perform the following steps:

1. Install a PostScript driver [for example, the Hewlett-Packard (HP)

   LaserJet IIIsi PostScript] from retail Windows 3.1.

2. In Control Panel, select that driver, and choose Setup, Options,

   Advanced, Edit Substitution Table.

3. Select Symbol as the TT font and Helvetica (or anything other than

   Symbol) as the Printer font to use.

4. Start Write (or Word for Windows, and so forth) and type some text in

   Helvetica. On the next line, type the same text using the Symbol font.

5. Print the document; the first line is in Helvetica and the second line

   is still in Symbol rather than Helvetica as expected.

Additional reference words: buglist3.10 True Type 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiFnt


BUG: CreatePatternBrush() with Large Bitmap GP Fault

Article ID: Q92531

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

On a machine with an 8514/a video adapter running the Microsoft Windows

graphical environment with the standard 8514/a video driver, when an

application calls the CreatePatternBrush() function to create a brush based

on a bitmap larger than 8 pixels by 8 pixels, Windows terminates the

application with an application execution error.

CAUSE

=====

Contrary to the documentation for the CreatePatternBrush() function on page

114 of the Microsoft Windows Software Development Kit (SDK) "Programmer's

Reference, Volume 2: Functions" manual, this function does not trim a

bitmap larger than 8 pixels by 8 pixels to this size.

STATUS

======

Microsoft has confirmed this to be a problem with Microsoft Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 gp-fault

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPnbr


BUG: Superclassed Scroll Bar's Parent Not Sent WM_CTLCOLOR Msg

Article ID: Q95391

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

---------------------------------------------------------------------

SYMPTOMS

========

Controls normally send WM_CTLCOLOR messages to their parents so

applications can modify the control background color. However,

under Windows 3.0 and 3.1, when a scroll bar is superclassed, its

parent is not sent WM_CTLCOLOR messages.

RESOLUTION

==========

Applications that want to receive the WM_CTLCOLOR message must

subclass the scroll bar rather than superclassing its window class.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0

and 3.1. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: 3.00 3.10 scrollbar buglist3.00 buglist3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: ProgMan DDE Reload() Command Does Not Work Properly

Article ID: Q95981

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Program Manager DDE Reload() command that is new for Windows 3.1

does not work as documented.

SYMPTOMS

========

Attempting to use the Reload() command in Windows version 3.1 for a

particular GroupName causes that Program Manager group to

disappear. On the other hand, not specifying any GroupName, which

supposedly instructs the Program Manager to unload all groups and

reload the [Groups] section of PROGMAN.INI, causes all the groups

to disappear.

RESOLUTION

==========

After all necessary modifications have been made, the Program

Manager DDE ReplaceItem() command may be used to delete the group

items that have changed; add them back again with the AddItem()

command.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version

3.1. This problem is scheduled to be corrected in the next Windows

version.

MORE INFORMATION

================

The DDE Reload() command documented in the Microsoft Windows version

3.1 Software Development Kit (SDK) "Programmer's Reference, Volume 1:

Overview" instructs Program Manager to remove and reload an existing

group. An application that modifies group files can use this command

to cause the Program Manager to update the groups when it has finished

making modifications.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrDde


BUG: PostScript Handles lfItalic Field Incorrectly

Article ID: Q96542

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows environment, when the Windows version 3.1

PostScript printer driver is installed and an application specifies a

nonzero value in the lfItalic member of a LOGFONT data structure to create

an italic font, text prints in a normal (nonitalic) font.

CAUSE

=====

The driver checks only the least-significant bit (LSB) of the lfItalic

field to determine whether the specified font is italic.

RESOLUTION

==========

Specify the value 1 to create an italic font.

MORE INFORMATION

================

The documentation for the lfItalic member of the LOGFONT data structure on

page 308 of the "Microsoft Windows Software Development Kit: Programmer's

Reference, Volume 3: Messages, Structures, and Macros" manual for version

3.1 states that an application can specify an italic font by placing any

nonzero value into this member. This procedure works correctly on all the

display and printer drivers provided with Windows 3.1 except for the

PostScript printer driver. The Windows version 3.0 PostScript printer

driver also accepts this procedure.

If the LSB is set, the driver selects an italic font. If the LSB is clear,

the driver selects a normal font. Therefore, placing a positive odd number

into the lfItalic member selects an italic font.

Additional reference words: buglist3.10 buglist3.00 3.10 3.00

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: Graphics Operations Consume GDI Memory

Article ID: Q98058

-------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

-------------------------------------------------------------------

SYMPTOMS

========

In the Microsoft Windows graphical operating environment, when a device

driver has rectangle capabilities (such as the 8514/a display driver) and

an application draws many large graphic objects, memory in the GDI data

segment is lost. Eventually, GDI runs out of memory and Windows crashes.

CAUSE

=====

GDI allocates a block of memory and then checks to see whether the device

has rectangle capabilities. If the device does have rectangle capabilities,

GDI calls into the device to let it do the drawing and does not free the

allocated memory.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

If the device does not have rectangle capabilities (for example, the

standard VGA display driver), GDI performs the drawing and frees the

memory. If an application is consuming GDI resources, run the application

on a machine with a VGA display. If GDI resources are not being consumed on

a VGA, then it is quite likely that the application has encountered this

bug.

Under certain circumstances, the following Windows application programming

interfaces (APIs) may encounter this problem:

   Drawing functions:

   Arc, Chord, Ellipse, Pie, Rectangle, RoundRect

   Region functions:

   CreateEllipticRgn, CreateEllipiticRgnIndirect, CreateRoundRectRgn

Third-party display-driver developers can avoid the GDI bug by not claiming

rectangle capabilities in the display driver. Just do not set the

PC_RECTANGLE bit in the dpPolygonals member of GDIINFO, and then rebuild

the driver.

Applications developers can use several approaches to avoid the problem

code. One approach is to create a memory device context (DC) and use it

instead of the display DC in the GDI functions. When complete, BitBlt the

memory DC to the screen DC. When using a compatible memory DC, the bug is

avoided because GDI performs the drawing instead of the driver.

The following code fragment demonstrates this approach:

   hMemDC = CreateCompatibleDC(hDC);

   hBitmap = CreateCompatibleBitmap(hDC, width, height);

   hOldBitmap = SelectObject(hMemDC, hBitmap);

   PatBlt(hMemDC, 0, 0, width, height, WHITENESS);

   /***

     Use hMemDC in all the GDI functions

     .

     .

     .

   ***/

   BitBlt(hDC, 0, 0, width, height, hMemDC, 0, 0, SRCCOPY);

   SelectObject(hMemDC, hOldBitmap);

   DeleteObject(hBitmap);

   DeleteDC(hMemDC);

The functions PatBlt, MoveTo/LineTo, Polyline, and FillRect are safe

alternatives to the drawing functions.

Additional reference words: buglist3.10 3.10 8514.DRV 8514 VGA.DRV

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: ETO_CLIPPED Does Not Clip Rotated Text

Article ID: Q99110

SYMPTOMS

========

In Microsoft Windows version 3.1, text output with a rotated

TrueType font is not clipped when the ETO_CLIPPED flag and a

clipping rectangle are specified in ExtTextOut().

CAUSE

=====

This problem is due to a bug in Windows.

RESOLUTION

==========

To work around this problem, create a rectangular clipping region,

select it into the device context, and do not specify the

ETO_CLIPPED flag or pass in a clipping rectangle to ExtTextOut().

For example:

   hRegion = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);

   SelectClipRgn(hDC, hRegion);

   ExtTextOut(hDC, x, y, 0, NULL, szText, lstrlen(szText), NULL);

   DeleteObject(hRegion);

STATUS

======

Microsoft has confirmed this to be a bug in Windows version

3.1. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 ExtTextOut clipping region

TrueType

KBCategory: kbprg kbbuglist

KBSubcategory: UsrPnt


BUG: Application Errors From Long Text in the Dialog Editor

Article ID: Q99134

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

An attempt to use the Dialog Editor provided with version 3.1 of the

Microsoft Windows Software Development Kit (SDK) fails and an application

error occurs under either of the following circumstances:

 - Choose Order/Group from the Arrange menu when the dialog box contains

   two or more controls, one control is a static text control, and the

   title of the text control is 256 characters long (the limit). (Setting

   a 256 character title may also generate a general protection [GP]

   fault.)

 - In test mode, enter more than 175 characters into a multiline edit

   control, then press BACKSPACE. A GP fault also occurs.

RESOLUTION

==========

Avoid using long names (more than 255 characters) for a static text control

and use the test mode carefully when the dialog box contains a multiline

edit control.

STATUS

======

Microsoft has confirmed this to be a bug in the Dialog Editor provided

with the Microsoft Windows Software Development Kit, version 3.1. We are

researching this problem and will post more information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

To re-create the first problem, perform the following seven steps:

1. Run the Dialog Editor.

2. Choose New from the File menu.

3. Click the static text control button on the toolbar.

4. Click in the dialog box to add a control to the dialog box.

5. Click the static text control button on the toolbar.

6. Click in the dialog box to add another control to the dialog box.

7. Choose Order/Group from the Arrange menu.

An application error occurs followed by a GP fault.

To re-create the second problem, perform the following nine steps:

1. Run the Dialog Editor.

2. Choose New from the File menu.

3. Click the edit control button on the toolbar.

4. Click in the dialog box to add a control to the dialog box.

5. Choose Styles from the Edit menu.

6. Select the Multiline option and choose OK.

7. Choose Test Mode from the Options menu.

8. Type more than 175 characters into the edit control.

9. Press BACKSPACE

An application error occurs followed by a GP fault.

Additional reference words: buglist3.10 3.10 GP Fault Exception 0x0D gpf gp-

fault

KBCategory: kbprg kbbuglist

KBSubcategory: TlsDlg


BUG: RC /fe Switch Does Not Work

Article ID: Q99670

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Specifying the /fe filename does not create a new executable file with the

specified filename. The Resource Compiler (RC) doesn't return an error

message indicating there is a problem. For example, when you specify

GENERIC.EXE to be renamed to BLAND.EXE with the following command line

   RC /fe BLAND.EXE GENERIC.RC GENERIC.EXE

BLAND.EXE is not created. Furthermore, the Resource Compiler doesn't tell

you that it encountered any problems.

CAUSE

=====

This is a bug in the resource compiler. The Resource Compiler code

overwrites the new filename with the filename given as the last parameter.

RESOLUTION

==========

To rename the executable to a filename different from the resource

filename, use the RENAME command from the MS-DOS command prompt.

STATUS

======

Microsoft has confirmed this to be a bug in the Resource Compiler in the

Microsoft Windows Software Development Kit (SDK) for Windows version 3.1.

We are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: 3.10 buglist3.10

KBCategory: kbtool kbprg kbbuglist

KBSubcategory: TlsRc


BUG: UngetCommChar() Causes Character Loss or GP Faults

Article ID: Q100183

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

An application that uses the UngetCommChar() function in Microsoft Windows

version 3.1 loses characters or experiences general protection (GP) faults.

CAUSE

=====

The ReadComm() function does not correctly account for a character buffered

by UngetCommChar().

RESOLUTION

==========

There are two methods to avoid this problem:

 - Modify the application to provide its own implementation of the

   UngetCommChar() function.

   -or-

 - Use version 3.0 of the Windows communications (comm) driver. This method

   should be used only if an existing application cannot be modified to

   work around this problem in Microsoft Windows version 3.1.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The UngetCommChar() function places a character into a single character-

holding variable. When ReadComm() is subsequently called, the character is

copied from the holding variable to the application's buffer before any new

characters are read from the comm driver.

If version 3.0 of the comm driver is installed, ReadComm() transfers the

remaining characters from the comm driver one character at a time by

calling the comm driver exported function RECCOM. During this process, the

application buffer pointer and character count variables are correctly

incremented and decremented, respectively.

However, if version 3.1 of the comm driver is installed, ReadComm()

transfers the remaining characters from the comm driver by a single

call to the comm driver exported function READCOMMSTRING. During this

process, the application buffer pointer is correctly incremented after

copying the character from the UngetCommChar() holding variable, but

the character count is not correctly decremented. This results in one

extra character being copied from the comm driver into the

application's buffer. The extra character is "lost" because the

application is not aware that an extra character has been read. This

can also cause a GP fault if copying an extra character to the

application's buffer exceeds the buffer segment limit. This problem

occurs only on the first ReadComm call that follows an UngetCommChar()

call. This problem never occurs if UngetCommChar() is never called.

Additional reference words: buglist3.10 3.10 gpf gp-fault

KBCategory: kbprg kbbuglist

KBSubcategory: KrCommapi


BUG: StretchDIBits() Prints Wrong Part of DIB with PSCRIPT.DRV

Article ID: Q100354

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

When using StretchDIBits() to print a section of a device-independent

bitmap (DIB) with the Windows version 3.1 PostScript printer driver,

in some cases the wrong part of the DIB is printed. When printing the

entire DIB, StretchDIBits() works correctly.

STATUS

======

Microsoft has confirmed this to be a bug in version 3.5 of the PostScript

printer driver (PSCRIPT.DRV) that shipped with Windows 3.1. The problem

also occurs with version 3.55 of the PostScript driver that is currently

available in the Windows Driver Library (WDL).

MORE INFORMATION

================

Below is the function prototype for StretchDIBits():

int StretchDIBits(hdc, XDest, YDest, cxDest, cyDest, XSrc, YSrc, cxSrc,

                  cySrc, lpvBits, lpbmi, fuColorUse, fdwRop)

HDC hdc;                      // Handle of device context

int XDest;                    // X-coordinate of destination rectangle

int YDest;                    // Y-coordinate of destination rectangle

int cxDest;                   // Width of destination rectangle

int cyDest;                   // Height of destination rectangle

int XSrc;                     // X-coordinate of source rectangle

int YSrc;                     // Y-coordinate of source rectangle

int cxSrc;                    // Width of source rectangle

int cySrc;                    // Height of source rectangle

const void FAR* lpvBits;      // Address of buffer with DIB bits

LPBITMAPINFO lpbmi;           // Address of structure with bitmap data

UINT fuColorUse;              // RGB or palette indices

DWORD fdwRop;                 // Raster operation

To print the entire DIB, set both XSrc and YSrc to 0 (zero). This

starting location of (0,0) corresponds to the bottom-left corner of

the DIB. If you do not want to print the bottom portion of the DIB,

change the starting location. Typically, you increase YSrc to the

desired value and leave XSrc at 0 (as well as adjusting cySrc

appropriately) so that the starting location is at the beginning of a

scan line in the DIB. If the value of YSrc is such that the distance

from the beginning of the DIB to (XSrc, YSrc) crosses a 64K segment

boundary, the wrong part of the DIB will be printed.

To print the top section of the DIB, the printer driver must adjust

lpvBits, the pointer to the DIB bits. Unfortunately, the segment

portion of the huge pointer to the DIB bits is not incremented

correctly; only the offset portion is incremented. Because the pointer

to the DIB bits is not adjusted correctly, it points to the wrong

section of the DIB bits and the wrong part of the DIB is printed.

Until the printer driver is fixed, application developers should

themselves adjust the pointer to the DIB bits. The values of the

biHeight and biSizeImage fields in the BITMAPINFOHEADER also must be

adjusted accordingly. All the necessary code to calculate the new

value for lpvBits can be obtained from the sample program DIBVIEW or

WINCAP.

For example:

 // PaletteSize() and WIDTHBYTES can be found in either DIBVIEW or WINCAP

 LPBITMAPINFOHEADER lpDIBHdr;  // Pointer to BITMAPINFO struct

                               // casted to LPBITMAPINFOHEADER

 LPSTR lpDIBBits;              // Pointer to DIB bits

 char _huge *lpTempDIBBits;    // IMPORTANT - must be a huge pointer

 DWORD  dwPalSize;             // Number of bytes in DIB color table

 DWORD  dwNumBytes;            // Number of bytes from beginning of DIB

                               // bits to (0, YSrc)

 DWORD  dwSize;                // Number of bytes from beginning of DIB

                               // to (0, YSrc)

 DWORD  dwSaveHeight;          // Save original DIB biHeight

 DWORD  dwSaveSizeImage;       // Save original DIB biSizeImage

...

 // Number of bytes in the DIB's color table.

 dwPalSize = PaletteSize((LPSTR)lpDIBHdr);

 // WIDTHBYTES calculates the number of bytes in one scan line.

 // dwNumBytes is the number of bytes from the beginning of the DIB

 // bits to the location (0, YSrc) in the DIB.

 dwNumBytes = YSrc * WIDTHBYTES(lpDIBHdr->biWidth * lpDIBHdr->biBitCount);

 // dwSize is the number of bytes from the beginning of the DIB to

 // the location (0, YSrc) in the DIB.

 dwSize = dwNumBytes + dwPalSize + (DWORD)sizeof(BITMAPINFOHEADER);

 if (dwSize >= 65536)

 {

    // Carefully adjust the pointer to the DIB bits.

    // Important Note: Due to problems with versions 6.0 and 7.0

    // of the Microsoft C Compiler, manipulating the pointer in one

    // statement may result in the segment portion of the huge pointer

    // being adjusted incorrectly or not at all.

    lpTempDIBBits = (char huge *)lpDIBBits;

    lpTempDIBBits = lpTempDIBBits + dwNumBytes;

    dwSaveHeight =  lpDIBHdr->biHeight;

    dwSaveSizeImage =  lpDIBHdr->biSizeImage;

    lpDIBHdr->biHeight -=YSrc;

    lpDIBHdr->biSizeImage= WIDTHBYTES(lpDIBHdr->biWidth *

                                      lpDIBHdr->biBitCount) *

                                      lpDIBHdr->biHeight;

    YSrc = 0;

 }

 if (!StretchDIBits (hDC,                           // DestDC

                     XDest,

                     YDest,

                     DestWidth,

                     DestHeight,

                     XSrc,

                     YSrc,

                     SrcWidth,

                     SrcHeight,

                     lpTempDIBBits,                 // DIB bits

                     (LPBITMAPINFO) lpDIBHdr,

                     DIB_RGB_COLORS,                // wUsage

                     SRCCOPY))                      // dwROP

    dwError |= ERR_PRN_STRETCHDIBITS;

 if (dwSize >= 65536)

 {

    lpDIBHdr->biHeight = dwSaveHeight;

    lpDIBHdr->biSizeImage = dwSaveSizeImage;

 }

For additional information on WINCAP, please see the following article in

the Microsoft Knowledge Base:

   ARTICLE-ID: Q97193

   TITLE     : SAMPLE: WINCAP Captures Screens Using DIB API

DIBVIEW can be found in the SAMPLES directory of version 3.1 of the

Windows Software Development Kit (SDK) and Visual C++ for Windows.

This is not an issue with Windows 95.

Additional reference words: 3.10 buglist3.10

KBCategory: kbtool kbprint kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: OpenFile() Fails When UNC Name Longer Than 11 Characters

Article ID: Q101414

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.11

--------------------------------------------------------------------

SYMPTOMS

========

OpenFile() successfully opens files with universal naming convention

(UNC) names when the server portion of the name is 11 characters or

shorter, but fails to open files when the server name is longer than

11 characters. Error code number 2, "File not found," is placed in the

nErrCode member of the OFSTRUCT structure passed to OpenFile.

CAUSE

=====

OpenFile() validates filenames before opening them, and in the case of

UNC names, allows server names that are 11 characters or shorter only.

No attempt is made to open a file with a UNC name longer than 11

characters.

RESOLUTION

==========

To open files with UNC names when the server name is longer than 11

characters, use _lopen().

STATUS

======

Microsoft has confirmed this to be a bug in the Windows SDK versions 3.1

and 3.11. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

This is not a problem under Windows NT WOW or under Windows 95.

MORE INFORMATION

================

This problem also affects the File Open common dialog box, because

GetOpenFileName() calls OpenFile().

Additional reference words: 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrFileIO


BUG: Extra CN_RECEIVE/CN_TRANSMIT Events

Article ID: Q101420

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

Using EnableCommNotification() to enable WM_COMMNOTIFY messages for

CN_RECEIVE or CN_TRANSMIT events can cause spurious WM_COMMNOTIFY messages.

At higher baud rates, this problem can cause a system to crash and reboot.

WM_COMMNOTIFY messages are received with a 0 (zero) value for the

NotifyStatus parameter. The system crashes and reboots while receiving or

transmitting data.

RESOLUTION

==========

If the application is experiencing these symptoms, possible solutions are:

 - Extra WM_COMMNOTIFY messages with NotifyStatus=0 can be ignored.

 - If the system is crashing, change the application to NOT enable

   CN_RECEIVE and CN_TRANSMIT events.

 - Enable the CN_EVENT notification for the EV_RXCHAR event by calling

   SetCommEventMask() then EnableCommNotification(). EV_RXCHAR is

   generated when any character is received and put into the queue. Make

   sure that EnableCommNotification() is called with -1 in both the

   cbWriteNotify and cbOutQueue parameters, such that the CN_RECEIVE and

   CN_TRANSMIT events are not enabled. This method is demonstrated in the

   TTY sample in the Windows Software Development Kit (SDK).

 - Instead of using EnableCommNotification, the application could poll

   for data. This could be implemented in the message loop of the

   application, or using a timer.

 - Modify COMM.DRV to work around this problem.

STATUS

======

This problem has been reported as a bug. There will not be a fix for

COMM.DRV in Windows version 3.1.

MORE INFORMATION

================

CN_RECEIVE events are generated when the number of bytes in the receive

queue exceeds the threshold (cbWriteNotify) set in EnableCommNotification()

or when a time-out occurs. After a CN_RECEIVE has been generated for

exceeding the cbWriteNotify threshold, another CN_RECEIVE should not be

generated until the number of bytes drops below cbWriteNotify then exceeds

it again.

CN_TRANSMIT events are generated similarly to CN_RECEIVE. The notification

threshold of the output queue is set in the cbOutQueue parameter of

EnableCommNotify. If the number of bytes in the output queue drops below

cbOutQueue, a CN_TRANSMIT should be generated. A new CN_TRANSMIT should not

be generated until the output queue exceeds, then drops below cbOutQueue

again.

However, if interrupts arrive fast enough, extra "threshold" CN_RECEIVEs

(or, similarly, CN_TRANSMITs) may be generated before the size of the

output queue drops below then again exceeds cbWriteNotify. These extra

events can be ignored; however, this characteristic may cause the system to

reboot, especially at higher baud rates.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrCommapi


BUG: DDESPY GP Faults Upon Return of CBR_BLOCK

Article ID: Q102549

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

DDESPY GP faults when a DDEML server application's dynamic data

exchange (DDE) callback function returns CBR_BLOCK from a transaction

of XCLASS_DATA class.

CAUSE

=====

Expecting to always obtain a valid data handle from transactions of

XCLASS_DATA class, DDESPY calls DdeAccessData() on the hData it

receives in an attempt to dump the data to its output window.

Internally, DDEML's DdeAccessData() translates to a GlobalLock() call.

Consequently, a return value of CBR_BLOCK (defined in WINDOWS.H as -1)

would mean calling GlobalLock() on an invalid hData == -1, and thus

results in a general protection (GP) fault.

STATUS

======

Microsoft has confirmed this to be a bug in the version of DDESPY

that comes with the Windows 3.1 SDK. With the improved parameter

validation in Windows NT, this problem should be corrected in the

Windows NT version.

MORE INFORMATION

================

In DDEML, transactions of XCLASS_DATA class are typically expected to

return a data handle. (Among the DDEML transactions of this class are

XTYP_REQUEST, XTYP_ADVREQ, and XTYP_WILDCONNECT.) However, in

situations where such transactions require lengthy processing (such as

a server gathering data from a network), thereby making it impossible

to return a data handle immediately, an application may choose to

return CBR_BLOCK from its DDE callback function. This allows the

server application to gather data "asynchronously," as DDEML queues up

further transactions on the current conversation.

Using DDEPSY to monitor this type of activity in the system results in

a GP fault, because DDESPY calls DdeAccessData() on an invalid hData

(== -1), as described in the CAUSE section above.

More information on DDEML transaction classes can be found in Section

5.8.7 of the Windows 3.1 SDK "Programmer's Reference, Volume 1:

Overview." More information on returning CBR_BLOCK to suspend DDEML

transactions may be found in Section 5.8.6 of the Windows 3.1 SDK

"Programmer's Reference, Volume 1: Overview," or by searching on the

following words in the Microsoft Knowledge Base:

   DDEML and CBR_BLOCK

Additional reference words: 3.10 GPF gp-fault buglist3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrDde


BUG: AddAtom Causes Divide by Zero Error

Article ID: Q103036

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

Calling the AddAtom function in the Windows 3.x environment with a

string that begins with the pound (#) character causes the system to

display the following error message in a system modal dialog:

   Application Error

   integer divide by 0

This error occurs if the first AddAtom call in the application passes

a string containing a # as the first character, and passes non-numeric

characters in the rest of the string. For example, the first call to

AddAtom with the string "#string" will cause the error to occur.

RESOLUTION

==========

If it is necessary to have atom strings beginning with the #

character, first call AddAtom with a false string that contains no #

characters. Alternatively, call InitAtomTable before adding the first

atom string beginning with the # character.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0

and 3.1. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

Atoms with names begin with the # character are strongly discouraged.

The # character serves a special purpose for atoms. If the string that

is passed to AddAtom has the form "#1234", AddAtom returns an integer

atom whose value is the 16-bit value representation of the decimal

number specified in the string. If the decimal value specified is 0

(zero) or a value in the range 0xC000 through 0xFFFF, the return value

is zero, indicating an error.

Sample Code

-----------

/* Compile options needed:  /Zp /GA or /GD or /Gw */

// errant code

{

 ATOM at;

 at = AddAtom("#string");     // causes error to occur

}

// corrected code

{

 ATOM at;

 InitAddTable(17);

 // or call AddAtom with a false string

 AddAtom("false");

 at = AddAtom("#string");     // no error occurs

}

Additional reference words: 3.00 3.10

KBCategory: kbprg kbbuglist kbcode

KBSubcategory: UsrDde


BUG: EV_RLSDS Event Does Not Indicate Current RLSD State

Article ID: Q103636

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

The EV_RLSDS communications event is documented as indicating the current

state of the RLSD (receive-line-signal-detect or carrier detect). However,

this event is never set.

SYMPTOMS

========

If SetCommEventMask() is used to enable the EV_RLSDS event, when

GetCommEventMask() is called, the EV_RLSDS bit will always be 0 (zero).

RESOLUTION

==========

To get the absolute state of RLSD, use the MSRshadow. For more information,

please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q101417

   TITLE     : Accessing the Modem Status Register (MSR) in Windows

STATUS

======

This will not be fixed in the Windows 3.1 COMM.DRV.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrCommapi


BUG: Iconic MDI Application Titles Do Not Update Properly

Article ID: Q104137

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

In a Windows 3.1 multiple document interface (MDI) application, the icon

title of the MDI frame window does not update when the SetWindowText

function is used to change the text of the icon title.

CAUSE

=====

In an MDI application, the main window calls DefFrameProc instead of

DefWindowProc to handle unprocessed messages. DefFrameProc does not handle

the WM_SETTEXT message (which is generated by SetWindowText) correctly when

the main window is minimized, because it does not update the title after

the change has been made.

RESOLUTION

==========

To update the minimized MDI frame's title, you can process the MDI frame's

WM_SETTEXT message and call both the DefFrameProc and DefWindowProc

functions. The following code demonstrates this workaround:

   case WM_SETTEXT:

       DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);

       return DefWindowProc (hwnd,msg,wParam,lParam);

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrMdi


BUG: SetDIBitsToDevice Faults on 24-BPP PM-Style DIBs

Article ID: Q104334

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

--------------------------------------------------------------------

SYMPTOMS

========

SetDIBitsToDevice faults inside GDI when passed a 24-bpp Presentation

Manager (PM) style device-independent bitmap (DIB) on a device that

supports RC_DIBTODEV.

CAUSE

=====

GDI must convert the old style BITMAPCOREINFO structure into a new

BITMAPINFO structure before passing it to a driver's RC_DIBTODEV function.

If the old style DIB has no color table, GDI will fault as it attempts to

append a zero length color table to the end of its temporary

BITMAPINFOHEADER.

RESOLUTION

==========

On devices that support RC_DIBTODEV, do the conversion into the new style

DIB format for GDI before calling into it when using 24-bpp PM-style DIBs.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 buglist3.00 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiBmp


BUG: StretchDIBits Faults on 24-BPP PM-Style DIBs

Article ID: Q104395

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

--------------------------------------------------------------------

SYMPTOMS

========

StretchDIBits faults inside GDI when passed a 24-bpp Presentation Manager

(PM) style device-independent bitmap (DIB) on a device that supports

RC_STRETCHDIB.

CAUSE

=====

GDI must convert the old style BITMAPCOREINFO structure into a new

BITMAPINFO structure before passing it to a driver's RC_STRETCHDIB

function. If the old style DIB has no color table, GDI will fault as it

attempts to append a zero-length color table to the end of its temporary

BITMAPINFOHEADER.

RESOLUTION

==========

On devices that support RC_STRETCHDIB, do the conversion into the new style

DIB format for GDI before calling into it when using 24-bpp PM-sytle DIBs.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiBmp


BUG: PALETTEINDEX Not Working for Thin Lines on HP PaintJet

Article ID: Q104962

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

In a Windows 3.1 printing application, calling the PALETTEINDEX macro to

select a color when drawing lines 1 pixel wide results in the printer

drawing black lines no matter what color index was selected from the

logical palette.

CAUSE

=====

When the PALETTEINDEX macro is used, a COLORREF value is returned. The

palette-entry index is placed in the low-order byte and a 1 is placed in

the high-order byte. When a pen is created with the CreatePen function and

a width of 0 (1 device unit) is placed in the nWidth field and a COLORREF

value returned from PALETTEINDEX is placed in the clrref field, the pen is

always black. The Hewlett-Packard (HP) PaintJet driver does not correctly

handle pens with a width of 1 pixel when a color is selected with

PALETTEINDEX and the high-order word of the COLORREF value is 1.

RESOLUTION

==========

Instead of using the PALETTEINDEX macro, you can use the PALETTERGB macro

to reference colors in your currently selected palette. Sometimes, this may

not be desirable because you would have to know all of the RGB values of

all indices in your logical palette. In that case, you could use the

GetPaletteEntries() function to retrieve the RGB values of the desired

logical palette index and call the PALETTERGB macro with those values.

Below is an example of how you could implement your own PALETTEINDEX

function. This function performs the same function as the PALETTEINDEX

macro, and works in all cases on the HP PaintJet.

   COLORREF MyPALETTEINDEX(HPALETTE hPalette, WORD wPaletteIndex)

      {

      PALETTEENTRY pe;

      GetPaletteEntries(hPalette, wPaletteIndex, 1, &pe);

      return (PALETTERGB(pe.peRed, pe.peGreen, pe.peBlue));

      }

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: SelectClipRgn() Does Not Update Properly on Printer

Article ID: Q104963

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

In a Windows 3.1 printing application, calling SelectClipRgn() with the

second parameter set to NULL to reset the clipping region to clip output to

the printer page does not reset the clipping region. Clipping on the

printer device context is still set to the clipping region specified in the

previous call to SelectClipRgn().

CAUSE

=====

The HP LaserJet II and HP LaserJet III printer drivers do not handle the

call to SelectClipRgn() properly when the hrgn parameter is set to NULL.

Instead of setting the clipping region to be the entire printable page (as

it should), the call has no effect and the previous clipping region is

still the device context's clipping region.

RESOLUTION

==========

Instead of sending NULL as the hrgn parameter to SelectClipRgn(), create a

region of the printable area of the page and send that region as the hrgn

parameter. This will give the desired effect of calling

SelectClipRgn(hPrnDC, NULL). The following is an example of how this

workaround could be implemented:

   HRGN hRgn,hPageRgn;

   POINT pt;

   SelectClipRgn(hPrnDC,hRgn=CreateRectRgn(200,200,500,500));

   // .  .  .

   // SelectClipRgn(hPrnDC,NULL);

   // Instead of calling the above function, try this:

   pt.x=GetDeviceCaps(hPrnDC,HORZRES);

   pt.y=GetDeviceCaps(hPrnDC,VERTRES);

   SelectClipRgn(hPrnDC,hPageRgn=CreateRectRgn(0,0,pt.x,pt.y));

   DeleteObject(hRgn);

   DeleteObject(hPageRgn);

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: SetPixel() Doesn't Work Properly on a PS Printer

Article ID: Q106018

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

In a Windows 3.1 printing application, calling the SetPixel() command on a

device context created for the Windows PostScript printer driver version

3.56 or earlier causes the pixel that is drawn to be larger than expected

if a line with a thickness greater than 1 was drawn previously.

CAUSE

=====

The PostScript driver's implementation of SetPixel() draws a circle with

the thickness set to the thickness of the last line drawn with the LineTo()

command if the thickness of the pen used is greater than 1.

STATUS

======

Microsoft has confirmed this to be a problem with the Windows PostScript

printer driver shipped with Windows 3.1. This problem has been corrected in

the PostScript driver for Windows NT.

RESOLUTION

==========

Instead of using the SetPixel() command, use the PatBlt() command to draw

the pixel. This is needed only if a pen of width greater than 1 was used to

draw lines with the Moveto() and LineTo() commands.

For example, if you were calling SetPixel() using the following line of

code to draw a black pixel at coordinates (10,10)

   SetPixel(hPrnDC, 10, 10, RGB(0,0,0));

instead of the above line of code, you could use PatBlt() in the following

way:

   PatBlt(hPrnDC, 10, 10, 1, 1, BLACKNESS);

MORE INFORMATION

================

Once a pen of thickness greater than 1 is created and selected into the

printer's device context and a LineTo() command is called, every call to

SetPixel() will result in a circle the width of the pen. If a pen of width

0 (zero) or 1 is created and used by the LineTo() command, the lines drawn

will be the correct thickness, but the SetPixel() command will still draw

with the thickness of the most recently used pen with a width greater than

1.

For example, the following code will draw the first two pixels correctly.

After the pen of width 50 is created and selected into the printer's device

context, the first call to SetPixel works correctly because LineTo() has

not been called yet. The call to SetPixel after the line is drawn results

in a circle the thickness of the line. After that, a pen of thickness 1 is

created and selected into the device context. The line drawn afterwards is

drawn correctly, but both calls to SetPixel() result in thick circles.

Sample Code

-----------

      if (StartDoc(hPrnDC,&di) > 0)

      {

         HPEN hPen, hPen2, hOldPen;

         StartPage(hPrnDC);

         hPen = CreatePen(PS_SOLID,1,RGB(0,0,0));

         hOldPen = SelectObject(hPrnDC,hPen);

         SetPixel(hPrnDC,100,10,RGB(0,0,0));

         MoveTo(hPrnDC,220,10);

         LineTo(hPrnDC,700,10);

         SetPixel(hPrnDC,800,10,RGB(0,0,0));

         hPen2 = CreatePen(PS_SOLID,50,RGB(0,0,0));

         SelectObject(hPrnDC,hPen2);

         SetPixel(hPrnDC,100,110,RGB(0,0,0));

         MoveTo(hPrnDC,220,110);

         LineTo(hPrnDC,700,110);

         SetPixel(hPrnDC,800,110,RGB(0,0,0));

         SelectObject(hPrnDC,hPen);

         SetPixel(hPrnDC,100,210,RGB(0,0,0));

         MoveTo(hPrnDC,220,210);

         LineTo(hPrnDC,700,210);

         SetPixel(hPrnDC,800,210,RGB(0,0,0));

         DeleteObject(hPen2);

         DeleteObject(SelectObject(hPrnDC,hOldPen));

         EndPage(hPrnDC);

         EndDoc(hPrnDC);

      }

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: System-Wide WH_DEBUG Hook Causes a GP Fault

Article ID: Q106077

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

Installing a system-wide hook of WH_DEBUG type causes a general protection

(GP) fault in the Windows SDK version 3.1.

CAUSE

=====

WH_DEBUG hooks are called before calling any other hooks in the system. The

bug occurs if at least one system-wide hook is present in the system.

(Shell installs one such system-wide hook.) In the process of reporting the

system-wide hook to the debug hook, the GP-fault occurs.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1. This problem is scheduled to be corrected in the next version.

Additional reference words: buglist3.10 3.10 gp-fault gpf

KBCategory: kbprg kbbuglist

KBSubcategory: UsrHks


BUG: Resolutions for DBWIN Utility Continuous Beeping

Article ID: Q108364

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

While running an application that has been compiled under debug mode, with

the DBWIN application running, the system may beep continuously causing the

computer to hang. This can happen when running the debug version of an

executable file in the debugger, or by just executing it.

CAUSE

=====

DBWIN uses an edit control for its output window. An edit box is limited to

approximately 32K total data. If this limit is exceeded, the system will

beep each time a new message is received by DBWIN. Depending on the

settings of the AFX.INI file, the messages sent can include TRACE messages,

main windows messages, WM_COMMANDS, and OLE (object linking and embedding)

trace messages.

RESOLUTION

==========

There are several possible solutions:

 - Instead of sending the output to the DBWIN window, the output can be

   directed to a monochrome monitor, which requires a monochrome adapter

   card and monitor installed on your system, or to a terminal connected

   to either COM1 or COM2 of the system.

   -or-

 - If the DBWIN application is set to output the DBWIN information to the

   window and then the DBWIN application is shut down, the debug output is

   instead sent to the output window of the Visual Workbench, which does

   not have the 32K limit.

   -or-

 - The SYSTEM.INI file can be set so that the debug output is directed to a

   file rather then to the debug window. The entry in the file should be

      [debug]

      OutPutTo=<filename>

   where filename is the full path of the file to which the debug output

   will be written. If there is not a debug section in your SYSTEM.INI file

   then you must add it.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows SDK,

version 3.1. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The source code for DBWIN is included as a sample in the Windows Software

Development Kit (SDK). It can be found under \MSVC\SAMPLES\DBWIN.

Additional reference words: 3.10 buglist3.10

KBCategory: kbtool kbprg kbbuglist

KBSubcategory: TlsDbg


BUG: GP Fault in LoadLibrary() with C++ DLL

Article ID: Q110180

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When loading a dynamic-link library (DLL) developed with Microsoft C/C++

7.0 or Visual C++ with a large number of exports not listed in the module

definition (.DEF) file, LoadLibrary() will cause a general protection (GP)

fault in Kernel with the message:

   Application Error

   MYAPP caused a General Protection Fault in module KRNL386.EXE at

   0002:0E8D

CAUSE

=====

The cause of the GP fault is the unusually large amount of exported

decorated C++ names in the resident name table in the executable header.

The Windows loader is not designed to handle the resident portion of the

executable header larger than 64K.

RESOLUTION

==========

The GP fault can be eliminated by reducing the size the resident name table

by listing the exported function names along with an ordinal number in the

EXPORTS section of the .DEF file. Because the compiler generates decorated

names, it is easier to copy the decorated function names from the .MAP file

to the .DEF file.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1 and Windows for Workgroups versions 3.1 and 3.11. We are researching

this problem and will post new information here in the Microsoft Knowledge

Base as it becomes available.

MORE INFORMATION

================

The error also occurs when loading the 16-bit DLL on Windows 95.

Although our linker does not support this feature, some 3rd-party

linkers such as OptLink has a switch that will automatically set the

names destined for the non-resident name table without doing the

copy/paste operation from the .MAP file to the .DEF file.

Additional reference words: 3.10 3.11 gpf gp-fault

KBCategory: kbprg kbbuglist

KBSubcategory: KrDll


BUG: Problem with DrawText Statement

Article ID: Q110487

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When the mapping mode is set to MM_LOMETRIC, DrawText does not properly

handle the "&" (ampersand) prefix character. The underscore character that

should go beneath the character that follows the "&" in the string is

appearing either elsewhere in the client area or not appearing at all.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrPnt


BUG: Palettes Realized in a Memory DC May Corrupt Screen

Article ID: Q110636

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

On a 256-color display, when a palette is realized into a memory device

context (DC), its colors are entered into the system palette, which may

corrupt the current screen.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The premise behind the Windows Palette Manager code is that the current top-

level window has priority over all other running applications in  letting

the system palette. When the active window sets a foreground palette, other

windows in the system that use the palette may have their colors changed if

there is not enough room for them to realize a background palette. This

behavior is normal and is expected. What is not expected is to have colors

change when a palette is selected and realized into a memory DC returned by

CreateCompatibleDC().

Additional reference words: buglist3.10 3.10 SelectPalette RealizePalette

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPal


BUG: SystemParametersInfo() Does Not Modify WIN.INI

Article ID: Q110662

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When a program uses the SystemParametersInfo() function with the

SPI_SETMOUSEBUTTONSWAP and SPIF_UPDATEINIFILE flags to reverse the mouse

buttons' orientation and modify WIN.INI, the appropiate changes to WIN.INI

are not made. The next time Windows starts, the buttons are back to the

default orientation.

CAUSE

=====

Calling SystemParametersInfo (SPI_SETMOUSEBUTTONSWAP, TRUE, NULL,

SPIF_UPDATEINIFILE), modifies or creates the SwapMouseButtons entry in

the "Windows" section of WIN.INI. However, the value this function writes

is "1", unlike the Control Panel's mouse applet which writes "Yes".

"Yes", not "1", is the value recognized to swap the buttons during the

startup of Windows. When Windows loads the settings from WIN.INI, Windows

looks for the "SwapMouseButtons" entry in the "Windows" section, expecting

a value of "Yes". If another value is encountered, Windows defaults to

"No", which will cause Windows to use the default orientation of the mouse

buttons.

RESOLUTION

==========

An alternative way to swap the mouse buttons and modify the entry correctly

is to use both SwapMouseButton() and WriteProfileString() to alter the

mouse button orientation and explicitly modify the initialization file. The

following code shows the method explained:

  :

  :

  SwapMouseButton (TRUE);

  WriteProfileString ("Windows", "SwapMouseButtons", "Yes");

  :

  :

STATUS

======

Microsoft has confirmed this to be a bug in the Microsoft Windows SDK

version 3.1. We will post new information here in the Microsoft Knowledge

Base when it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrIni


BUG: DDEML Fails to Free Item Name HSZ on a LATEACK

Article ID: Q110664

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

On an advise loop started with the XTYPF_ACKREQ flag, the item name string

is mistakenly removed from the global atom table after a certain period

of time causing a subsequent call to DdePostAdvise() on that item name

string to fail.

CAUSE

=====

For an advise loop started with the XTYPF_ACKREQ flag, DDEML sends the

server application an XTYP_ADVREQ with the LOWORD(dwData1) set to

CADV_LATEACK when the server application calls DdePostAdvise() before the

ACK for the previous update has been received.

When the server's callback returns from processing this specific

transaction, DDEML fails to free the item name string handle. This causes

the item name's atom reference count (a WORD value) to increment

indefinitely. When the maximum number of transactions (65535 for a WORD

value) of this type occur, the reference count will be incremented

(wrapped) to zero and the item name's atom ultimately is deleted from the

global atom table. Subsequent calls to DdePostAdvise() on this item name

string fail because the item name is no longer valid.

RESOLUTION

==========

To work around this problem, modify your 16-bit server code as described

below, freeing the string handle appropriately before returning from the

XTYP_ADVREQ transaction:

   case XTYP_ADVREQ:

   ....  // Application specific processing here.

   if (WIN16APP &&  (GetDDEMLVer() <= 0x00030011))

   {

      if (CADV_LATEACK == LOWORD(dwData1)

          DdeFreeStringHandle(idInst, hsz2);

   }

   ...  // Return appropriate data handle or NULL here.

The function GetDDEMLVer() could be written to return the dwFileVersionMS

member of the VS_FIXEDFILEINFO structure. Refer to the VERSTAMP sample that

shipped with the Microsoft Windows 3.1 SDK and/or Microsoft Visual C++ for

further details about extracting version information.

WIN16APP can be #defined to TRUE if this is a 16-bit version of your

application; FALSE otherwise.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1.

NOTE: This is not a problem in the 32-bit version of DDEML, that is, the

version that comes with Microsoft Windows NT and Windows 95.

Additional reference words: 3.10 buglist3.10

KBCategory: kbprg kbbuglist kbcode

KBSubcategory: UsrDde


BUG: Ampersand in Menu Item Is Not Converted

Article ID: Q110713

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

If a menu item has tabbed or right-justified text that contains a mnemonic

access character, an ampersand ("&") will appear in front of the desired

access character and the character will not be underlined.

If the menu item has a cascading menu associated with it, the right-

justified text may partially overwrite the arrow that indicates the

presence of a submenu.

CAUSE

=====

An ampersand in a menu item string is normally translated into an underline

character and used as the mnemonic access character for that menu item. If

an ampersand occurs in tabbed or right-justified text, however, it will not

cause the character following it to be underlined. Instead, the ampersand

and the access character will be literally displayed as they appear in the

string. Windows does not examine tabbed or right-justified text in menu

strings to determine if the text contains an ampersand that needs to be

converted into an underscore.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

Although the access character does not appear underlined in the menu, the

menu item can still be selected by typing the access character. Windows

correctly interprets the ampersand as signaling a mnemonic character, but

does not correctly display the string.

An example menu item string that demonstrates the problem is:

  "Start\aCtrl+&G"

In this example, the menu item is "Start", and the keyboard shortcut

(accelerator) is CTRL+G. When the menu item is displayed, the ampersand and

the "G" will be shown as they appear in the string rather than being

converted into an underlined "G".

"The Windows Interface: An Application Design Guide" from the Windows SDK

makes a distinction between the menu item and the text that indicates the

keyboard shortcut.

Each menu item should have a mnemonic access character associated with it.

The use of a mnemonic in a keyboard shortcut is thus non standard.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrMen


BUG: MoveTo/LineTo Causes Divide by 0 Error

Article ID: Q111007

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SYMPTOMS

========

Using MoveTo() or LineTo() with a delta X or delta Y greater than 16K to

draw within a complex clipping region, causes the system to display the

following error message in a system modal dialog box:

   Application Error

   integer divide by 0

CAUSE

=====

If the change in x or the change in y in the MoveTo/LineTo calls is greater

than 16K, and if the line is being drawn to a complex clipping region, a

divide overflow error occurs in GDI.EXE. This problem does not occur for

smaller changes in x or y, and it also does not occur if the line is being

drawn to a noncomplex clipping region.

RESOLUTION

==========

This bug can be worked around by avoiding complex clipping regions, or if

complex regions are critical, by ensuring that the changes in x and y in

MoveTo/LineTo calls are always less than 16K.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Gaps Between Wedges Drawn with Pie()

Article ID: Q111008

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Under certain circumstances, the Windows Pie() API will leave gaps between

pie wedges when there should be a solid line.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

Pie() takes the following parameters:

   BOOL Pie( HDC hdc,

             int nLeftRect,

             int nTopRect,

             int nRightRect,

             int nBottomRect,

             int nxStartArc,

             int nyStartArc,

             int nxEndArc,

             int nyEndArc )

Pie() draws a pie-shaped wedge by drawing an elliptical arc whose center

and two endpoints are joined by lines.

Using Pie(), if two pie wedges are drawn with the same bounding rectangle

and the end point of the first wedge is equal to the start point of the

second wedge, there can be a gap between adjacent wedges. This gap shows up

only with certain pie sizes and certain start/end points.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: DDE Warning Message: Invalid Value: -32767

Article ID: Q111013

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When executing a call to DdeClientTransaction() from a Microsoft

Foundation Class (MFC) Library application in the debug version of Windows

3.1, the following warning message is displayed in the debug monitor:

   wn  CLIENTAPP  CallNextHookEx + 2C: Invalid value: -32767"

CAUSE

=====

This error message is caused by the _AfxMsgFilterHook hook procedure

installed by MFC. This hook procedure, found in line 408 of the file

APPCORE.CPP of the MFC 1.0 source, incorrectly passes internal DDEML

messages to the CallNextHookEx() function. When the hook procedure receives

a MSGF_DDEMGR message, it should return FALSE instead.

For additional information, please see the following article(s) in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q89828

   TITLE     : Do Not Forward DDEML Messages from a Hook Procedure

RESOLUTION

==========

Although this warning message is generally harmless, one way to prevent

this message is to modify the _AfxMsgFilterHook function in the APPCORE.CPP

file (found in \MSVC\MFC\SRC directory for Microsoft Visual C++ version

1.0) to return FALSE if (code == MSGF_DDEMGR), as the KB article above

recommends, and then rebuild the library.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Foundation

Classes version 1.0 that comes with Microsoft Windows Software Development

Kit (SDK) version 3.1 for Windows. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 3.10 buglist3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrDde


BUG: Nonscrolling Region in Help File Topic Does Scroll

Article ID: Q111095

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

A Windows Help file topic that has been formatted to provide a nonscrolling

region does scroll.

CAUSE

=====

A BUILDTAGS section was used in the Help project file to exclude the

preceding topic from the build. The subsequent topic with formatting for a

nonscrolling region will behave as if it was not formatted to be a

nonscrolling region. In other words, the region will scroll.

STATUS

======

Microsoft has confirmed this to be a bug in the Help Compiler version

3.1. We are researching this problem and will post new information here as

it becomes available.

MORE INFORMATION

================

Formatting for a nonscrolling region is specified by using the RTF \keepn

format or by using the "Keep Paragraph With Next" command in Word for

Windows.

Additional reference words: buglist3.10 3.10 Help Compiler non-scrolling

KBCategory: kbtool kbbuglist

KBSubcategory: TlsHlp


BUG: Size of Owner-Draw Drop-Down Combo Box in Dialog Is Wrong

Article ID: Q111096

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When creating an owner-draw drop-down combo box in a dialog box, the size

of the static portion is not the same as a non-owner-draw combo box in the

same dialog box. WM_MEASUREITEM is not being processed, and therefore the

size of the owner-draw combo box and non-owner-draw combo box should be the

same.

CAUSE

=====

When creating a dialog box, the Dialog Manager determines how big the owner-

draw combo box should be based on the system font. If you specify a font in

your dialog box resource, this font should be used rather than the system

font in determining the size of the controls. Unfortunately, the Dialog

Manager uses the system font when determining the size of the static

portion of an owner-draw combo box, regardless of whether a different font

has been specified in the dialog box resource.

RESOLUTION

==========

To circumvent this problem, process the WM_MEASUREITEM message, specifying

the height of the items in your combo box. Windows correctly sizes the

static portion when you handle the WM_MEASUREITEM message.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 combobox ownerdraw dropdown

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: SetWindowPos() on an Iconic Window and its Caption

Article ID: Q111335

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

SetWindowPos() is called on a minimized window to either move or hide the

window. When moving, the window is moved but the caption is left behind.

When Hiding, the window is hidden but the caption is still visible.

RESOLUTION

==========

Use SetWindowPlacement() instead of SetWindowPos().

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrWndw


BUG: R2_XORPEN Binary ROP Code Ignored for Wide Pens

Article ID: Q111336

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

If a wide pen is selected in a device context and SetROP2() is called to

set the binary raster-operation (ROP) code to R2_XORPEN, the desired effect

is not achieved for ellipses, arcs, roundrects, or rectangles. The ROP is

basically ignored.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Pie() and Arc() Functions Fail with a Wide Pen

Article ID: Q111337

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When creating a wide (multiple pixel) pen and drawing a reasonably large

object, the drawing function returns 0 (zero) or does not draw anything.

Choosing a thin (single pixel) pen or choosing a pen smaller than X pixels

corrects the problem.

CAUSE

=====

GDI builds a polygon that basically puts a circle on every point along the

pen's path and calls Polygon() to fill it. If the point data or the working

storage of Polygon() exceeds 64K, the call is failed.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The following are examples that reproduce the problems in Windows version

3.1.

Pie() Function

--------------

When selecting a bold pen [second parameter of CreatePen() is greater than

7] and calling Pie() as follows, nothing is drawn; however, the return

value of Pie() indicates that it was drawn:

   hPen=CreatePen(PS_SOLID,9,0L);

   SelectObject(hDC,hPen);

   Pie(hDC, 96, 11, 839, 754, 440, 12, 479, 11);

Arc() Function

--------------

The Arc() function returns an error value when called as follows, even

though the width and height are both within the documented limits of 32767:

   Arc( hDC, -11047, -3493, 806, 8360, 311, 64, 356, 170 );

                x1      y1   x2    y2   X3  Y3   X4   Y4

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Vector Font Rotation Skewed with Non-Top-Left Alignment

Article ID: Q111338

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Vector fonts do not rotate properly with a text alignment set to other than

the top left.

To reproduce this problem, create a logical font for the Script vector

font. Call SetTextAlign() to set the text alignment to TA_BASELINE and

TA_CENTER. Rotate the font, perhaps in a whirl pattern as the FONTEST

sample does. Note that the rotation axis is skewed in the northwest-

southeast direction. This problem occurs in all mapping modes.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10 TA_TOP

TA_LEFT

KBCategory: kbprg kbbuglist

KBSubcategory: GdiFnt


BUG: Text Truncated in Edit Control

Article ID: Q111341

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Copying and pasting a very large block of text in a multiline edit control

may result in part of the text being truncated or some of the text being

misaligned. This problem is more likely to happen when using a large size

font instead of the default font for the edit control.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

When pasting the text, the default window procedure for the edit control

calls the ExtTextOut() function to display the text. The last parameter to

ExtTextOut() is int FAR* lpDx, which specifies the spacing between

character cells. For a very long string, there may not be enough stack

space for the entire lpDx array, and therefore the string is truncated.

When this happens, if you are running the debugging version of Windows, you

will see the message "not enough stack space for DX array. String

truncated."

Additional reference words: buglist3.10 3.10 edit control multi-line

truncate

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: LineTo() Endcaps Misaligned with Large Pen Width

Article ID: Q111576

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

If LineTo() is used with a wide pen selected, the endcaps are misaligned

with the line; they are skewed at an angle relative to the line.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

To reproduce the problem, select a black pen of width about 100:

   MoveTo(hDC,207,73)

   LineTo(hDC,512,251)

Look at the endcaps; they cause the line to appear twisted or deformed.

NOTE: To invalidate the area, the following was used:

   Rect.top=Y1-nCurPenWidth/2-1

   Rect.left=X1-nCurPenWidth/2-1

   Rect.bottom=Y2+nCurPenWidth/2+1

   Rect.right=X2+nCurPenWidth/2+1

If nCurPenWidth is greater than 103, then the endcaps are not completely

erased, and fall outside the Rect area.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10 end caps

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Rotated TrueType Font Repaints Many Times

Article ID: Q111579

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Drawing a rotated TrueType font into a nonrectangular clipping region

causes the font to be drawn many (perhaps a hundred) times.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 flash repaint

KBCategory: kbprg kbbuglist

KBSubcategory: GdiTt


BUG: Some ROP Codes Cause Inconsistent Polygon() Line Segments

Article ID: Q111580

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When a ROP (raster operation) such as R2_XORPEN or R2_NOT is used with the

Polygon() function, the line segments may be inconsistent; they may appear

highlighted or ragged when they should appear smooth. This may be more

apparent when the polygon is filled with a gray brush (80h).

CAUSE

=====

The border does not overlap the interior fill precisely. Polygonal filling

works successfully, but the XOR operation with the pen shows that the

overlap between border and fill is not completely consistent.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The following function demonstrates the problem:

int PASCAL TestProc( HWND hWnd )

{

    HDC hDC;

    HBRUSH hGrayBrush, hOldBrush;

    POINT aPoints[3];

    hGrayBrush = CreateSolidBrush(RGB(128,128,128));

    aPoints[0].x = 50;

    aPoints[0].y = 10;

    aPoints[1].x = 250;

    aPoints[1].y = 50;

    aPoints[2].x = 125;

    aPoints[2].y = 130;

    hDC = GetDC(hWnd);

    // default pen, brush, and ROP2

    Polygon(hDC, aPoints, sizeof(aPoints) / sizeof(POINT));

    // default pen, gray brush, XORPEN ROP2

    hOldBrush = SelectObject(hDC, hGrayBrush);

    SetROP2(hDC, R2_XORPEN);

    Polygon(hDC, aPoints, sizeof(aPoints) / sizeof(POINT));

    // clean up

    SelectObject(hDC, hOldBrush);

    ReleaseDC(hWnd, hDC);

    return 1;

}

Additional reference words: buglist3.00 buglist3.10 3.00 3.10 ropcode code

uneven

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Pie() Vertex Not Drawn Completely with Wide Pen

Article ID: Q111581

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When calling Pie() with a wide pen selected, the vertex of the pie slice is

not drawn correctly. The wide lines do not meet at the vertex.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

This behavior may be reproduced as follows on an 8514 display:

With a pen of width of about 30, call Pie() with the following parameters:

   X1=197, Y1=179, X2=969, Y2=638, X3=334, Y3=525, X4=810, Y4=181

At the center of the pie, the wide lines forming the vertex of the pie

slice do not meet flush. A wedge is not filled in.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Arc() Not Drawn Completely with a Wide Pen

Article ID: Q111582

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When calling Arc() with a wide pen selected, occasionally there will be an

unfilled line in the third quadrant of the arc.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

This behavior may be reproduced as follows on a VGA display:

With a pen width of 100 selected into the DC, call Arc() with the

following parameters:

   X1=165, Y1=12, X2=445, Y2=294, X3=279, Y3=142, X4=227, Y4=20

There will be a slanted line of width 1 (one) that is not drawn in the pen

color.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Occasional Gap Between Adjacent Pie() Wedges

Article ID: Q111584

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

If the Pie() function is used to draw two pie wedges with the same bounding

rectangle and the end point of the first wedge is equal to the start point

of the second wedge, there can be a gap between adjacent wedges. This gap

only occurs occasionally, and with certain pie sizes and start-and-end

points.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

This behavior can be reproduced using the following code fragment on a VGA

display:

Sample Code

-----------

#define     xLeft     (25)

#define     yTop     (25)

#define     xRight     (450)

#define     yBottom     (450)

#define     xMiddle     ((xLeft + xRight) / 2)

#define     yMiddle     ((yTop + yBottom) / 2)

{

HBRUSH hbrushRed, hbrushBlue, hbrushOld;

hbrushRed = CreateSolidBrush(RGB(255, 0, 0));

hbrushBlue = CreateSolidBrush(RGB(0, 0, 255));

hbrushOld = SelectObject(hdc, hbrushRed);

Pie(hdc, xLeft, yTop, xRight, yBottom, xRight, yMiddle, xRight, yTop);

SelectObject(hdc, hbrushBlue);

Pie(hdc, xLeft, yTop, xRight, yBottom, xRight, yTop, xMiddle, yTop);

SelectObject(hdc, hbrushOld);

DeleteObject(hbrushRed);

DeleteObject(hbrushBlue);

}

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: GetRasterizerCaps Returns Zero When TrueType Is Disabled

Article ID: Q111586

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When TrueType is disabled from the Control Panel, GetRasterizerCaps()

returns zero (failure) instead of clearing the TT_ENABLED flag in the

RASTERIZER_STATUS structure.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiTt


BUG: _lread() Functions Incorrectly When No Floppy in Drive

Article ID: Q111587

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Using the function _lread() to read a floppy disk when there is no disk in

the floppy drive results in the System error-message box "Cannot Read from

Drive..." with Retry and Cancel buttons. If the Cancel button is clicked,

_lread() returns, indicating incorrectly that it read the number of bytes

requested. Instead, it should return -1, indicating failure.

RESOLUTION

==========

Before calling _lread(), call SetErrorMode() in your application to disable

the default Windows Critical Error Handler so that the system error-message

box will not be displayed. The _lread() function will correctly return -1,

indicating failure.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 int24

KBCategory: kbprg kbbuglist

KBSubcategory: KrFileIO


BUG: OpenFile() Doesn't Handle Forward Slash ("/") Character

Article ID: Q111588

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

OpenFile() does not correctly handle paths beginning with a forward slash

character ("/") (for example, as in "x:/").

CAUSE

=====

The forward slash character "/" is put into the normalized name as is,

instead of being converted to a backslash character ("\"). OpenFile() is

not implemented to check for the forward slash character.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 backward

KBCategory: kbprg kbbuglist

KBSubcategory: KrFileIO


BUG: Brush Misaligned in PaintRgn()

Article ID: Q111589

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

In a mapping mode other than MM_TEXT with the background mode set to

TRANSPARENT, when calling PaintRgn() to paint a nonrectangular region with

a hatched brush, the brush is misaligned.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

To work around this problem, call SetMapMode() to switch to the mapping

mode MM_TEXT before calling PaintRgn().

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Some TrueType Character Pairs Run Together on VGA

Article ID: Q111590

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

On some displays such as the standard VGA display that ships with Windows

3.1, certain TrueType font character pairs do not have any space between

them and run together. For example, when using the Arial TrueType font at a

point size of 14 or greater, the characters "f7" don't have any space

between them.

CAUSE

=====

The standard VGA display driver does not support one-pass opaquing of the

entire glyph black box so GDI must simulate. The simulation is not done

correctly for certain characters.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

If you are using TextOut() to display the text and this slight cosmetic

problem is not acceptable, you can use the ExtTextOut() function and

specify the spacing between the characters.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDisplay


BUG: IsBadStringPtr() Reports Bad String as Valid

Article ID: Q111591

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Under a particular condition, IsBadStringPtr() will report that a bad

string is valid. If the pointer passed to IsBadStringPtr() refers to a

block of memory of size 0xFFFF and is filled with all nonzero data,

IsBadStringPtr() returns 0.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

For IsBadStringPtr() to validate a string, it must be passed a pointer to

valid memory and the string must contain a NULL character that terminates

the string.

The following code illustrates the error:

#include <windows.h>

#include <windowsx.h>

#include <memory.h>

LPSTR lpPtr;

BOOL fRet;

     // GlobalAllocPtr is a macro in WINDOWSX.H

lpPtr = GlobalAllocPtr(GMEM_MOVEABLE, 0XFFFF);

_fmemset(lpPtr, 'Q', 0xFFFF);

Ret = IsBadStringPtr(lpPtr, 0xFFFF);

if (fRet)  // ... etcetera, fRet incorrectly contains zero.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrMisc


BUG: DeleteObject() Generates Debug Errors in WEP

Article ID: Q111592

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Freeing GDI objects in the Windows Exit Procedure (WEP) of a dynamic-link

library (DLL) will generate errors from the debug version of Windows 3.1.

The errors are incorrectly generated if the application has an implicit

link to the DLL and the application is terminating.

CAUSE

=====

The debug version of Windows reports errors that a task has exited but has

not freed any GDI resources allocated by the task. Windows calls the WEP of

an implicitly linked DLL when the DLL is unloaded from memory but after the

application using the DLL has already exited. Debug Windows interprets this

situation as an error and gives debug messages in DBWIN or the debug

terminal.

RESOLUTION

==========

Although debug Windows reports the GDI objects are not freed, The WEP is

still called and the objects are still freed regardless of the messages

displayed by debug Windows. There is no need to call DeleteObject(). These

messages can be ignored.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrDll


BUG: DPMI Function 0203h Does Not Report Error

Article ID: Q111593

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Using the MS-DOS Protected Mode Interface (DPMI) function 0203h (set

processor exception handler vector) to set an exception handler does not

report an error (carry flag set) if the selector:offset pair is invalid.

RESOLUTION

==========

The pointer to the exception handler must be validated with other means if

it is necessary to check the pointer for validity. Other means of checking

a code pointer for validity include using IsBadCodePtr() or the LAR (load

access rights) protected-mode CPU instruction.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The problem with DPMI function 0203h can be illustrated with the following

code segment:

   mov     edx, dword ptr BogusOffset

   mov     cx, word ptr BogusSelector

   ; Set Processor Exception Handler Vector

   mov     ax, 203h

   mov     bx, 7

   int     31h

   jc      Error       ; never jumps to Error

REFERENCE

=========

The IsBadCodePtr() function is documented in the Windows 3.1 SDK

"Programmer's Reference, Volume 2: Functions" manual. The LAR instruction

is documented in the Intel 386 or 486 "Programmer's Reference" or in

"Microsoft's 80386/80486 Programming Guide" by Microsoft Press.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrDpmi


BUG: Dr. Watson Fails to Write Log File

Article ID: Q111596

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Assume that the drive for the Windows directory is substituted using the MS-

DOS SUBST command. For example:

   subst w: c:\win31

Under this condition, Dr. Watson fails to write to its log file, either the

default DRWATSON.LOG or any other changed log filename. In fact, when the

Dr. Watson icon is double-clicked, the message box that follows shows the

log filename as W:\\DRWATSON.LOG, which is incorrect.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 gpf gp-fault trap gp fault

KBCategory: kbprg kbbuglist

KBSubcategory: TlsDrWatson


BUG: Debug Kernel Ignores Fatal Exits When OutputTo=

Article ID: Q111597

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

By default, the Windows debugging kernel sends its debug messages to the

AUX device (which maps to the COM1 port). When the debug output from the

Windows kernel is redirected by using OutputTo=NUL or OutputTo=<filename>

in the [DEBUG] section of the SYSTEM.INI file, Fatal Exit messages are

ignored automatically.

RESOLUTION

==========

This behavior is by design of the Windows debugging kernel and there is no

other flag to control the output of Fatal Exit messages even if you have a

serial terminal connected to the COM1 or COM2 port.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrDebug


BUG: Opaque Rectangle Too Small on Rotated TrueType Fonts

Article ID: Q111598

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When a TrueType font is rotated, the text background is too small to

completely enclose the glyphs; the same text unrotated is enclosed.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

You can reproduce this problem by running the FONTTEST sample, selecting

Arial 72 pt, setting the lfEscapement to 450, and typing in "ff" in the

String window. Note how the upper-right part of the "f" goes outside the

background rectangle.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiTt


BUG: Character Background Is Not Painted Correctly

Article ID: Q111599

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When text is displayed on a window with a background different than the

background of the DC (used to display the text), slivers will display

between the characters. The slivers seem to occur only between certain

character combinations, such as "Th".

This problem is only evident with some drivers, such as the standard VGA.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiFnt


BUG: Polygons Drawn with Pens of Odd Width (> 5) Misalign

Article ID: Q111600

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When drawing frames with Polygon(), if the pen width results in an odd

number of pixels (and therefore cannot be centered exactly on its

coordinates), the extra pixel of width goes up and/or to the left for

widths greater than 5 pixels, whereas it correctly goes down and to the

right for widths less than or equal to 5 pixels.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

More Information

================

Using the ShowGDI sample, the following steps reproduce the problem:

1. Start the ShowGDI sample and maximize it.

2. Set the pen width to 5.

3. Choose Polygon from the Draw menu and enter 4 for the number of points.

   Enter the following ordered pairs for the points 0 through 4: (20,20)

   (40,20) (40,40) (20,40).

Note that a 5-pixel frame correctly puts the extra pixel of pen width to

the right and/or below the 20 and 40 coordinate lines (resulting in two

pixels up and left, and three pixels down and right). This is correct (as

are 1- and 3-pixel thick lines). However, odd widths of greater than or

equal to 7 pixels start to round in the wrong direction:

4. Choose Clear from the View menu.

5. Choose Width from the Pen menu and enter 7 for the width.

6. Repeat step 3 above.

Now the extra pixels goes up and to the left, resulting in 4 up/left and 3

down/right.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Misleading Default Pushbutton Painting

Article ID: Q111601

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Under some conditions in Windows 3.0 and Windows 3.1, more than one

pushbutton (or Command button)(style BS_PUSHBUTTON) may be painted with the

dark border used to designate a default pushbutton. A default pushbutton is

the pushbutton designated to be activated when the user presses the ENTER

key.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 push button push-button

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: GetPrivateProfileInt() May Not Read Correct Value

Article ID: Q111602

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

If GetPrivateProfileInt() is used to read a number that has preceding white

space, the value returned may be incorrect. For example, if the .INI file

entry is as follows, GetPrivateProfileInt() may return 0 (zero):

   MyValue= 5

CAUSE

=====

This problem is caused by the white space in front of the number.

RESOLUTION

==========

Ensure that any numbers written to an .INI file do not contain white space.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 whitespace

KBCategory: kbprg kbbuglist

KBSubcategory: UsrIni


BUG: GlobalCompact() May Return an Inaccurate Value

Article ID: Q111603

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

GlobalCompact() may return a very inaccurate value when paging is enabled.

CAUSE

=====

This is the value that is returned by a DPMI call. It is simply the largest

hole in the linear address space and is not necessarily the largest block

that can be allocated.

RESOLUTION

==========

Allocate only as much memory as needed, and always check the return value

from a call to a memory allocation routine.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrMm


BUG: Explicitly Loaded Modules Not Removed from Memory

Article ID: Q111604

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Modules that are loaded via LoadModule() are not removed from memory when a

GP (general protection) fault causes the application that loaded it to

terminate. You must exit Windows to unload the module.

CAUSE

=====

Windows does not currently maintain information about what loaded a

specific module.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: KrTsksIns


BUG: LoadResource() GP Faults When Passed an Invalid HRSRC

Article ID: Q111605

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Passing an invalid handle as the HRSRC parameter for LoadResource() may

result in a general protection (GP) fault.

RESOLUTION

==========

Pass only valid handles to the LoadResource() function.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 gpf gp-fault

KBCategory: kbprg kbbuglist

KBSubcategory: UsrRsc


BUG: ROP2 Code Applied Incorrectly in Pie() Function

Article ID: Q111606

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

When calling the Windows SDK function Pie() using a ROP2 code other than

the default R2_COPYPEN, and using a pen with a width greater than 1 (one),

you may notice that the pie border is not drawn correctly.

CAUSE

=====

The pen position is applied incorrectly and overlaps part of the interior.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

For a demonstration of this bug, run the sample program SHOWGDI that comes

with the Windows 3.1 SDK or with Microsoft Visual C++. Set the pen width to

greater than 1 and make sure that the pen color and brush color are

different. For example, set the pen width to 5 and the pen color to

RGB(0,255,0). Set the brush color to RGB(255,0,255). Set the ROP2 code to

R2_XORPEN and then draw a pie. You will see three color ranges. The pen

position is applied incorrectly and overlaps part of the interior.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: LB_SETTOPINDEX Doesn't Conform to Documentation

Article ID: Q111647

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Code written to handle a return of LB_ERR does not function properly.

The online documentation for LB_SETTOPINDEX states that the result is

LB_ERR if an error occurs. However, when an error occurs, LB_SETTOPINDEX

returns with a value of 0 (zero) rather than LB_ERR.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 buglist3.00 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: EM_CANUNDO Returns Zero After EM_REPLACESEL

Article ID: Q111648

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

EM_CANUNDO returns 0 (zero) after text in an edit control has been set or

replaced using EM_REPLACESEL. EM_CANUNDO should return nonzero, and EM_UNDO

should undo the change.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.1. We

are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: Left Part of Character Is Clipped with ExtTextOut/TextOut

Article ID: Q111649

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The left part of a TrueType character such as an italic "f" is clipped.

CAUSE

=====

There is a bug in the TextOut() and ExtTextOut() functions that occurs with

complex clipping regions. In this case, GDI considers the left edge of the

string to be the X coordinate used in the TextOut() or ExtTextOut() call.

This works for bitmap fonts, but not TrueType fonts because the "A" part of

a TrueType font's ABC width may be negative (as it normally is with an

italic "f").

Because this problem only occurs with complex clipping regions, the

character may appear to be randomly clipped as the clipping region changes.

For example, clipping may be tied to the presence of a dialog box or other

window over the client area, because that may create a complex clipping

region.

RESOLUTION

==========

An application can correct this problem by calling ExtTextOut() and passing

in a clipping rectangle that accounts for the portion of the text going to

the left of the starting point.

For example, in the following call, the string origin is offset within the

clipping rectangle so the string will not be clipped:

   ExtTextOut(hdc, rc.left+10, // text origin (offset by 10 into cliprect)

              rc.top, ETO_CLIPPED,

              &rc, "ffff", 4, NULL);

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1.

This problem does not occur in Windows 95.

MORE INFORMATION

================

Steps to Reproduce Problem

--------------------------

This problem can be reproduced in Windows Write as follows:

1. Start Write.

2. Switch to the Times New Roman Italic font in a 72 point size and type

   an "f".

3. Display Write's About box and move it off of the "f". When the window is

   repainted, the left serif of the "f" will be clipped.

Additional reference words: buglist3.10 3.10 sporadic

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: DrawFocusRect Fails in MM_LOMETRIC or MM_ISOTROPIC Mode

Article ID: Q111650

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SYMPTOMS

========

If DrawFocusRect() is called when the mapping mode is MM_LOMETRIC or

MM_ISOTROPIC, no rectangle is drawn.

DrawFocusRect() is documented to take logical units and works properly in

MM_TEXT mapping mode. However, if the mapping mode is changed to

MM_LOMETRIC or MM_ISOTROPIC, as in the following code fragment,

DrawFocusRect() called with an appropriate rectangle (logical units) does

not work. Calling Rectangle() with the same rectangle does work.

   case WM_PAINT:

         hDC = BeginPaint(hWnd, &ps);

            SetRect(&rc, 0,0,100,100);

            DrawFocusRect(hDC, &rc);      // Works as documented.

            SetMapMode(hDC, MM_LOMETRIC);

            SetRect(&rc, 1,-200,100,-300);

            DrawFocusRect(hDC, &rc);     // Doesn't do anything.

       Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom); // Works

            EndPaint(hWnd, &ps);

            break;

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.10 3.00

KBCategory: kbprg kbbuglist

KBSubcategory: UsrInp


BUG: GetGlyphOutline() with GGO_BITMAP Fails with Large Scale

Article ID: Q111651

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Calling GetGlyphOutline() for a bitmap and passing a large X or Y scaling

factor in the transformation matrix causes the return value to not properly

track the bitmap size.

For example, Times New Roman Regular 72 point "1", with a scaling factor of

4.0 in eM11 of the transformation matrix, returns a black box of 100,64.

This requires a bitmap of at least 800 bytes but GetGlyphOutline() only

returns 256. The native buffer is returned with no problems.

CAUSE

=====

A 12-point font on a VGA is marked to use the rasterizer's scan converter.

However, if the scaling indicated in the transform exceeds the outline

threshold, GDI's "external" scan converter should be used. Unfortunately,

that condition is not detected.

NOTE: This problem occurs only with bitmaps; outlines are fine with all

transformation matrices.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 truetype font

KBCategory: kbprg kbbuglist

KBSubcategory: GdiTt


BUG: Edit Controls and WS_CLIPCHILDREN Function Differently

Article ID: Q111652

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Unnecessary painting is done when an edit control window is created with

the WS_CLIPCHILDREN style bit set.

CAUSE

=====

If an edit control window is created with the WS_CLIPCHILDREN style bit

set, a WM_PAINT message will be sent to the parent. In Windows version 3.0,

the rcUpdate is (0,0,0,0), which makes it very easy to ignore this WM_PAINT

message. In Windows version 3.1, the rcUpdate is the size of the child edit

control, which causes extra painting to be done. The WM_PAINT message is

not necessary because the child control itself does the painting, not the

parent.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: Printer Driver Receives "bigfonts" When Not Supported

Article ID: Q111653

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

If the installed display driver of a Windows 3.1 installation supports

raster fonts that are greater than 64K, then any printer driver on the

system is expected to support the fonts, even if [GetDeviceCaps(hPrnDC,

RASTERCAPS) & RC_BIGFONT] returns NULL for the printer driver.

CAUSE

=====

In some cases, the printer driver will call the display driver to perform

certain GDI operations. Windows expects that 64K and greater fonts will

eventually be drawn by the display driver instead of the printer driver.

This assumption causes Windows to believe that a printer driver will

support these fonts, even if it does not.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10 bigfonts big fonts

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: StretchDIBits Not Correctly Stretching RLE DIBs w/ Jumps

Article ID: Q111654

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Calling StretchDIBits() to stretch an RLE device-independent bitmap (DIB)

with jumps in it results in random garbage being displayed.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiBmp


BUG: StretchBlt() Does Not Perform Palette Translations

Article ID: Q111729

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Normally, the StretchBlt() function performs a palette translation when the

destination and source bitmaps do not contain the same color format or

palette. When the destination rectangle is the exact size of the source

rectangle (no stretching is performed), the palette translation is not

performed.

CAUSE

=====

When the destination and source rectangles are the same size, no stretching

is performed and BitBlt() is called to perform a straight copy of the

source to the destination. BitBlt() does not perform the palette

translation that StretchBlt() does.

RESOLUTION

==========

You can force StretchBlt() to not call BitBlt() by changing one of the

destination rectangle coordinates by one unit. Then, the palette

translation will be performed.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

This problem does not occur in Windows NT version 3.1.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiBmp


BUG: TabbedTextOut() in Metric Mapping Mode Incorrect

Article ID: Q111862

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When using TabbedTextOut() in one of the metric mapping modes, a rectangle

is displayed in the current background color above the text that is

displayed. This rectangle is the width and height of the line of text. The

text is displayed with a background that is the current background color.

However, the space between the text (where the tab is) is not displayed

with a background that is the current background color.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: Driver vs. GDI-Simulated Styled Lines Don't Match

Article ID: Q111863

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Lines drawn using the same styled pen may appear slightly different. For

example, when drawing styled lines with the R2_XORPEN raster operation to

draw and remove lines quickly, some pixels may be left behind.

CAUSE

=====

GDI's styled line simulation does not match pixel-for-pixel the display

driver's styled line drawing. Styled lines are drawn either by GDI or by

the display driver depending on the driver's line and clipping

capabilities. Even if a driver supports styled lines, it may not handle

styled lines when clipping is involved. In the situations not handled by

the driver, GDI will simulate the styled line, thus exhibiting differences

in pixels.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPnbr


BUG: GP Fault When Drawing on a Memory-Based DC

Article ID: Q111864

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

A general protection (GP) fault can occur on a memory-based device context

(DC) when a bitmap previously selected in the DC is selected out and

another is selected in. This is a common problem when using the SaveDC()

and RestoreDC() functions with a memory DC.

CAUSE

=====

In a regular (nonmemory-based) DC, when the SaveDC() and RestoreDC()

functions are used, the size of the window client area of the DC does not

change. The size of the drawable area in a memory-based DC is dependent on

the size of the current bitmap selected in the DC.

For example, suppose the default 1 x 1 monochrome bitmap is selected in a

memory DC and you call SaveDC(). Now, you select a 200 x 200 color bitmap

into the DC and you perform some drawing commands. Then, you call

RestoreDC() to restore the DC. This action will select the old 1 x 1 bitmap

back into the DC. Unfortunately, GDI does not update the clipping region

when this happens, and when you draw outside the 1 x 1 region, you can

receive a GP fault.

RESOLUTION

==========

After you call RestoreDC() on a memory-based DC, you need to call

SelectObject() to select the bitmap that was selected in the DC before

RestoreDC() was called.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1. We are

researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

The following code exhibits the problem outlined above. When

CreateCompatibleDC() is called, a default 1 x 1 monochrome bitmap is

selected into the DC returned from the function. By restoring the initial 1

x 1 bitmap after getting a visible region of 200 x 200, GDI thinks the 1 x

1 surface has a clipping rectangle of 200 x 200. This is what causes the

overwrite.

Sample Code

-----------

   HBITMAP hbm1,hbm2;

   HDC     hdcBits,hdcScreen;

   hdcScreen = GetDC(NULL);

   hdcBits = CreateCompatibleDC(hdcScreen);

   hbm1 = CreateCompatibleBitmap(hdcScreen,200,200);

   hbm2 = CreateCompatibleBitmap(hdcScreen,200,200);

   SaveDC(hdcBits);

   SelectObject(hdcBits,hbm1);

   PatBlt(hdcBits,0,0,200,200,WHITENESS);

   RestoreDC(hdcBits,-1);

   SaveDC(hdcBits);

   SelectObject(hdcBits,hbm2);

   PatBlt(hdcBits,0,0,200,200,WHITENESS);

   Ellipse(hdcBits,0,0,200,200);

   RestoreDC(hdcBits,-1);

   Rectangle(hdcBits,0,0,200,200);

Additional reference words: buglist3.10 3.10 gpf gp-fault 1x1 200x200

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDc


BUG: StretchBlt()/StretchDIBits() Fail with Very Large Stretch

Article ID: Q111865

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

If the stretching factor is large, for example, when stretching from a very

small to a large height, StretchDIBits() and StretchBlt() may return 0

(zero) and display nothing. The same bitmap with a smaller stretch is

displayed correctly.

CAUSE

=====

Most display drivers do not implement their own StretchBlt() or

StretchDIBits() so GDI must simulate these calls. Part of the GDI

simulation involves allocating temporary work buffers, which are limited to

64K. If the size of the work buffer is calculated to be greater than 64K,

then the height of the source and destination rectangles are halved until

they are less than 64K. The problem is that if GDI must continue to divide

the height by two (2) to get a buffer less than 64K, the source or

destination height could eventually reach one scan line. At this point, the

call fails because it cannot break up a scan line into subunits.

StretchBlt() and StretchDIBits() are not designed to provide unlimited

stretching. However, they may fail a bit more prematurely than their design

limitation.

RESOLUTION

==========

If StretchBlt() or StretchDIBits() fails on a large stretch, an application

can divide up the source bitmap, stretch the pieces individually, and

position them correctly once stretched. Another alternative is to do a

smaller stretch. There is no formula to determine exactly what bitmaps will

fail at what stretch size.

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

To reproduce the problem, create a bitmap approximately 2048 pixels wide by

16 pixels high. Then, display the bitmap with the DIBVIEW sample from the

Windows 3.1 SDK. Choose Stretch To Window from DIBVIEW's Options menu, so

that the bitmap is stretched according to the size of the client window.

When the height is more than about 200 pixels, the bitmap will not be

displayed.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10 fail zoom

KBCategory: kbprg kbbuglist

KBSubcategory: GdiBmp


BUG: Outline of a Pie() Slice May Not Be Completely Smooth

Article ID: Q111866

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The outline of a Pie() slice may not be completely smooth.

CAUSE

=====

Windows calculates the Pie() center using device points. Round-off errors,

especially in mapping modes other than MM_TEXT, can put the center of the

pie off center, resulting in a slightly "crinkly" pie slice.

RESOLUTION

==========

The bounding rectangle of the Pie() function includes the top left

coordinates (X1,Y1) but not the bottom right coordinates (X2,Y2). Adding

1 to X2 and Y2 makes the real extent even, and therefore the radius can be

nicely placed. But this method works on the screen only in the default

MM_TEXT mode. If you change the mapping of the device context to some high

resolution mode, such as MM_HIENGLISH or MM_TWIPS, the center again goes

off 1 by pixel and you get slightly crinkly pie slices.

Windows converts all four pairs of coordinates of the Pie() function from

logical points to device points, and then it calculates the center of the

pie. If you're going from a high resolution mode to a low resolution

device, such as the screen or a 75 dpi printer, you'll get rounding errors.

As a workaround, an application can do a DPtoLP() of (1,1) and add that to

X2 and Y2. For example, in MM_HIENGLISH, the result of the DPtoLP() of

(1,1) is about 13 logical points instead of just 1. Note, however, that

this method will not work all the time, because the rounding error will

depend on the actual coordinates.

If an application requires smooth pie slices, and must use a mapping mode

other than MM_TEXT, the application could proceed as follows (this does

defeat the purpose of using a mapping mode):

1. Call LPtoDP() for all four coordinate pairs.

2. Make sure the coordinate pairs are proper and will allow a true center

   for the pie.

3. Call DPtoLP() on the coordinate pairs.

4. Pass the coordinates to Pie().

STATUS

======

Microsoft has confirmed this to be a bug in Windows versions 3.0 and

3.1. We are researching this problem and will post new information here

in the Microsoft Knowledge Base as it becomes available.

Additional reference words: buglist3.00 buglist3.10 3.00 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: GdiDrw


BUG: GetTimerResolution not in LIBW.LIB

Article ID: Q112386

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

When using the Windows Application Programming Interface (API)

GetTimerResolution() function, you may get unresolved externals from the

linker.

CAUSE

=====

The function is in USER.EXE but is not referenced in the import library

LIBW.LIB.

RESOLUTION

==========

To work around the problem, import the function using the IMPORTS section

of the DEF file as shown below:

IMPORTS

   GetTimerResolution=USER.GetTimerResolution

STATUS

======

Microsoft has confirmed this to be a bug in the Windows SDK version

3.1. We are researching this problem and will post new information here as

it becomes available.

Additional reference words: buglist3.10 3.10 SetTimer WM_TIMER

KBCategory: kbprg kbbuglist

KBSubcategory: UsrTim


BUG: General Protection Fault When Accessing an HFONT

Article ID: Q114013

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

On rare occasions, in low memory situations or after calling the function

GlobalCompact(-1), a general protection fault (GPF) may occur when calling

SelectObject() to select a handle to a logical font (HFONT) into a device

context. This happens when the application caches the handle to the logical

font.

CAUSE

=====

Part of the internal data structure for the font resides in global memory

that is allocated as GMEM_DISCARDABLE. In tight memory situations, this

global memory may be discarded and GDI does not detect this situation

before attempting to access the memory.

STATUS

======

Microsoft has confirmed this to be a bug in Windows version 3.1.

This problem does not occur in Windows 95.

MORE INFORMATION

================

To avoid this bug, applications should not cache font handles but instead

hold onto the LOGFONT structure that contains the information for

recreating the font. By holding onto the LOGFONT and calling the function

CreateFontIndirect() each time a font is needed, applications should be

able to safely avoid this bug.

NOTE: The call to CreateFontIndirect() is not an expensive call in terms of

performance. The actual mapping of logical font to physical font happens

when you call SelectObject(). When you cache HFONTs, you still have to call

SelectObject() each time before calling any of the Windows text APIs so

this approach only requires one additional function call.

Additional reference words: buglist3.10 3.10 font fault error

KBCategory: kbprg kbbuglist

KBSubcategory: GdiFnt


BUG: DDESPY and Ctrl Key Cause GP Fault in Windows NT

Article ID: Q114530

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Visual C++ for Windows, version 1.5

----------------------------------------------------------------------

SYMPTOMS

========

The 16-bit DDESpy utility, supplied with the Windows SDK version 3.1 and

Visual C++ for Windows version 1.5, can cause a general protection (GP)

fault in KRNL386.EXE when the CTRL key is pressed. This problem only occurs

when running DDESPY under Windows NT version 3.1.

STATUS

======

Microsoft has confirmed this to be a bug in the 16-bit DDESpy version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

This problem does not occur with Visual C++ 2.0 32-bit Edition.

Steps to Reproduce Problem

--------------------------

1. Start DDESPY.

2. Select the Track menu item from the main menu.

3. Select the Services menu item.

4. An icon titled Registered Servers will appear. Double click on the

   icon to maximize the window.

5. Press CTRL+ESC to bring up the Task List. The GP fault will occur at

   this point.

Additional reference words: buglist3.10 DDE spy 3.10

KBCategory: kbtool kbbuglist

KBSubcategory: TlsSpy


BUG: Caching GDI Objects Causes Temporary GDI Resource Leak

Article ID: Q118471

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

The amount of free GDI resources decreases as an application prints,

especially over the course of several print jobs.

NOTE: The information in this article also applies to the screen; however,

this issue more often impacts applications when printing, and therefore

that is the specific subject of this article.

CAUSE

=====

The application caches GDI objects by creating them and not deleting them

until the application terminates. Those objects are selected in and out of

a printer device context (DC) when needed, over the course of several print

jobs.

GDI creates a new physical object structure for each logical object that is

selected into a printer DC. New physical objects are created even if the

same logical objects are selected into a different printer DC. Those

physical objects are not deleted until the corresponding logical objects

are deleted. The more objects used in printing, and the more jobs that are

printed using those objects, the more physical objects are created and more

GDI resources are used up.

RESOLUTION

==========

Do not cache GDI objects (such as pens, brushes, and fonts). Instead,

create them, use them during printing, and then delete them after each

print job.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

This problem can be reproduced as follows:

1. Create a logical object such as a pen, brush, or font.

2. Repeatedly:

   a. Create a printer DC.

   b. Select the object into and out of the printer DC.

   c. Delete the printer DC.

With each iteration, GDI memory decreases.

Additional reference words: buglist3.10 3.10 buglist3.10 system resources

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: MCIWndClass Popup Window Palette Flashes

Article ID: Q121330

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Video for Windows, version 1.1

---------------------------------------------------------------------

SYMPTOMS

========

An MCIWndClass popup window realizes its logical palette in the foreground

instead of the background as requested in a call to MCIWndRealize() with

the fBkgnd flag set to TRUE. The foreground palette realization is seen as

a flash.

The following code demonstrates the setting that results in the flash. The

flash occurs when the popup window receives the input focus from another

application using a different logical palette.

   hwndPanel = MCIWndCreate(hwndParent, hInst,

      MCIWNDF_NOAUTOSIZEMOVIE | MCIWNDF_NOMENU |

      WS_OVERLAPPED | WS_BORDER | WS_CAPTION |

      WS_SYSMENU | WS_POPUP, NULL);

   MCIWndOpen(hwndPanel, fname, 0);

   MCIWndRealize(hwndPanel, TRUE);

   SetWindowPos(hwndPanel, HWND_TOP, X, Y, 0, 0,

      SWP_NOSIZE | SWP_DRAWFRAME | SWP_SHOWWINDOW);

   MCIWndPlay(hwndPanel);

CAUSE

=====

When the MCIWndClass popup window receives the input focus from another

application that uses a different logical palette, the popup window

receives a WM_QUERYNEWPALETTE message that is processed for the popup

window by the MCIWndProc() procedure. In the MCIWndProc() procedure, the

"case WM_QUERYNEWPALETTE:" results in a call to MCIWndRealize() with the

flag fBkgnd set to FALSE. This occurs even if the popup window's palette

was originally realized in the background.

STATUS

======

Microsoft has confirmed this to be a bug in Microsoft Video for Windows

Version 1.1. We are researching this problem and will post new information

as it becomes available in the Microsoft Knowledge Base.

MORE INFORMATION

================

The problem described in the SYMPTOMS section occurs only with popup

windows. It does not arise when the window style is WS_CHILD. When the

window is a child window, the WM_QUERYNEWPALETTE messages are processed by

the parent window's callback procedure instead of the MCIWndProc()

procedure.

When the window involved is a popup window, you can avoid the flash by

subclassing the MCIWndProc() procedure and allowing the subclassing

application to process the WM_QUERYNEWPALETTE message directly by calling

MCIWndRealize() with the fBkgnd flag set to TRUE. The following code

demonstrates this workaround:

// MakeProcInstance() is called once in a convenient place such

// as the application's InitInstance() procedure. RealizeProc()

// is the procedure that subclasses MCIWndProc(). RealizeProc()

// will process WM_QUERYNEWPALETTE messages on behalf of

// MCIWndProc(). In the Module Definition File, list the

// RealizeProc() procedure under EXPORTS.

   lpfnRealizeProc = MakeProcInstance((FARPROC)

      RealizeProc, hinstCurrent);

// In the application's MainWndProc() under "case WM_DESTROY:",

// call FreeProcInstance().

   FreeProcInstance(lpfnRealizeProc);

// Add the next two function calls to the code shown in the

// Symptoms section just after the call to MCIWndCreate(). The

// GetWindowLong() call returns a pointer to the popup window's

// original window procedure, namely MCIWndProc(). The

// SetWindowLong() procedure specifies that the RealizeProc()

// procedure is the new window procedure for the popup window.

   lpfnOldRealizeProc = (FARPROC)GetWindowLong(hwndPanel,

      GWL_WNDPROC);

   SetWindowLong(hwndPanel, GWL_WNDPROC, (LONG)

      lpfnRealizeProc);

// The following procedure subclasses MCIWndProc(). It processes

// the WM_QUERYNEWPALETTE messages. All other messages

// are sent to MCIWndProc(), which is pointed to by the

// parameter lpfnOldRealizeProc.

long FAR PASCAL RealizeProc(HWND hwndPanel, UINT message, WPARAM

               wParam, LPARAM lParam)

{

   switch (message)

   {

      case WM_QUERYNEWPALETTE:

         return (MCIWndRealize(hwndPanel, TRUE));

      default:

         return (CallWindProc((WNDPROC)lpfnOldRealizeProc,

            hwndPanel, message, wParam, lParam));

   }

}

Additional reference words: 3.10 1.10 mci buglist3.10 buglist1.10

KBCategory: kbmm kbbuglist kbtool kbusage

KBSubcategory: MMVideo


BUG: GetOutlineTextMetrics() Returns Bad Data in Japanese Win

Article ID: Q123146

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for the Japanese

   version of Windows version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

Under Japanese Windows version 3.1, the fields otmpFamilyName,

otmpFaceName, otmpStyleName, and otmpFullName of the OUTLINETEXTMETRIC

structure (obtained by calling the GetOutlineTextMetrics() function)

contain garbled data.

For example, when True Type Arial Bold is selected, GetOutlineTextMetrics()

returns:

otmpFamilyName: Ailal

otmpFaceName: AilBl

otmpStyleName: Bl

otmpFullName: Wntp:ra odVrin1(irsf)ersion 1 (Microsoft)

CAUSE

=====

This problem is caused by a bug in the modules translating the True Type

font descriptions from UNICODE to ANSI.

STATUS

======

Microsoft Japan has confirmed this to be a bug in Japanese Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available. This problem does not

exist in U.S. Windows version 3.1.

Additional reference words: Win3.1J WIFE FESDK

KBCategory: kbprg kbbuglist

KBSubcategory: WIntlDev


BUG: True Type Font Display Problem with WINHELP ver 3.10.151

Article ID: Q123332

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SYMPTOMS

========

WINHELP.EXE version 3.10.151 is included in Traditional Chinese Windows

version 3.1. When displaying help files using WINHELP.EXE version 3.10.151,

large English characters ( 24pts and above) in True Type Font have a

distorted appearance. Large True Type Font Chinese characters in the same

help file are not affected. Non-True-Type-Font characters are not affected.

STATUS

======

Microsoft Japan has confirmed this to be a bug in Japanese Windows version

3.1. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: fesdk WIFE

KBCategory: kbtool kbbuglist

KBSubcategory: WIntlDev


BUG: WinG 1.0 Bug List

Article ID: Q124741

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft WinG API, version 1.0

----------------------------------------------------------------------

SYMPTOMS

========

Microsoft has confirmed the items in the following list to be bugs in the

Microsoft WinG API.

 - Some Western Digital drivers cause the WinG display profiler to crash.

   The second time a WinG application is run, the profiler will not run and

   WinG will attempt to use the driver's StretchDIBits without profiling.

   This may or may not let the application run depending on what caused the

   original crash.

 - The WinG installation will not work on networked Windows installations

   (setup /n) because the WinG setup program needs to write to the system

   directory.

 - If your application needs to link to TOOLHELP, you must call TOOLHELP's

   LibMain before you call WinG. Work-arounds include changing the DLL

   initialization order, or linking dynamically to WING.DLL or

   TOOLHELP.DLL. If you are using Microsoft Visual C++, you can change the

   initialization order by following these steps:

   1. Go to Project/Edit and check the list of files you have in the

      project. If you have included WING.LIB, delete it.

   2. Go to Options/Project/Linker/Input/Windows Libraries and clear the

      TOOLHELP selection.

   3. Go to Options/Project/Linker/Input/Input and hard code the

      locations of TOOLHELP.LIB, followed by WING.LIB and then the rest

      of the libraries as usual. For example:

      C:\MSVC\LIB\TOOLHELP, C:\WING\LIB\WING, oldnames, libw, mlibcew

 - Video cards using the Cirrus Logic chipset may cause WinG to display the

   following warning each time WinG is loaded; once should be enough:

      WinG has encountered a problem with your video display driver.

      Contact the manufacturer of your card to obtain the most recent

      driver. Your WinG applications will still run, but at reduced speed.

 - When WinG closes down, it leaks selectors, the memory is freed when the

   WinG DLL exits.

 - On Win32s, calls to WinGGetDIBColorTable() do not retrieve the color

   table of a WinG bitmap. Possible work-arounds include keeping track of

   the color table yourself or thunking to the 16-bit

   WinGGetDIBColorTable().

STATUS

======

Microsoft has confirmed these to be bugs in WinG version 1.0. Microsoft is

researching these problems and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: 1.00

KBCategory: kbprg kbbuglist

KBSubcategory: WinG


BUG: ExtractIcon Not Freeing Up Memory

Article ID: Q125049

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SYMPTOMS

========

Calling ExtractIcon() with a -1 as the iIcon parameter to obtain the total

number of icons in a file results in a loss of system resources. Each time

an application calls ExtractIcon() in this manner, the system loses some

resources. However, when the application that called ExtractIcon()

terminates, the resources are freed. This situation can cause low memory

conditions when an application that is running calls ExtractIcon() many

times to find the number of icons in a number of different files.

CAUSE

=====

The problem occurs when you call ExtractIcon() with the iIcon parameter set

to -1 in order to count the number of icons. ExtractIcon() erroneously

omits a GlobalFree call that is supposed to free some intermediate global

memory used to count the number of icons in the specified file. As a

result, each call made to ExtractIcon() in this manner results in a loss of

memory and an occupied selector until the application terminates.

RESOLUTION

==========

To work around the problem, you can extract consecutive icons in a file

until ExtractIcon() fails. This will give you the total number of icons in

the file without memory loss.

STATUS

======

Microsoft has confirmed this to be a bug in the products listed at the

beginning of this article. We are researching this bug and will post new

information here in the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

Below is a function that you could call to retrieve the number of icons in

a file:

int NumIcons(HINSTANCE hinst, LPCSTR lpszExeName)

   {

   int i = 0;

   HICON hIcon;

   while (hIcon = ExtractIcon(hinst,lpszExeName,i))

     {

     i++;

     DestroyIcon(hIcon);

     }

   return (i);

   }

Additional reference words: 3.1

KBCategory: kbbuglist kbprg

KBSubcategory: GdiCurIco GdiCurIcoMisc


BUG: EM_LIMITTEXT Causes GPF in Japanese and Chinese Windows

Article ID: Q126820

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1 (Japanese and Traditional Chinese)

----------------------------------------------------------------------

SYMPTOMS

========

Under the Japanese and Traditional Chinese versions of Windows version 3.1,

if an edit control has style ES_AUTOHSCROLL, and EM_LIMITTEXT is sent to

the edit control to limit the number of bytes the user can input to the

edit control, a general protection fault (GPF) will occur when the user is

entering a double-byte character for the last byte.

For example, if the following function is used to limit the number of bytes

a user can input to 7:

   SendMessage (hWnd, EM_LIMITEXT, 7, NULL);

The user enters "ABCDEF"( all single-byte character) to the edit

control, then try to enter a double-byte 'G' to the edit control, a

GPF will occur.

Also, a GPF will also occur under the Japanese version of Windows version

3.1, if EM_LIMITTEXT is used and the edit control has style ES_UPPERCASE

and the edit control is using the MS MINCHO or MS GOTHIC font.

Hangeul (Korean) Windows version 3.1 does not GPF if EM_LIMITTEXT is used

along with the ES_UPPERCASE style and the MS MINCHO or MS GOTHIC font.

RESOLUTION

==========

Subclass the edit control, and check the WM_CHAR message coming in. If the

WM_CHAR message for the last byte is a DBCS leadbyte, discard the

WM_CHAR message along with the next WM_CHAR message. The following code

demonstrates this workaround:

LONG FAR PASCAL SubClassFunc(HWND hWnd,

                             WORD Message,

                             WORD wParam,

                             LONG lParam)

{

static BOOL bInvalidchar=FALSE; // Is this the last byte?

   if ( Message == WM_CHAR )

   {

      if (bInvalidchar==TRUE) //The trailing byte of a DBCS character

      {                       //that comes in for the last byte in edit.

         bInvalidchar=FALSE;  //Reset the flag. Next char is valid.

         return 0;            //Throw away the trailing byte.

      }

      else

      {

         // Is this the last byte?  Is the incoming WM_CHAR a DBCS

         //   leadbyte?

         if ( IsDBCSLeadByte(LOBYTE(wParam)) &&

            (( TEXTLIMIT - SendMessage(hWnd, WM_GETTEXTLENGTH, 0,0)) == 1))

         {

            bInvalidchar=TRUE;   //The character is invalid.

            return 0;               // Throw away this byte.

         }

         else return CallWindowProc(lpfnOldWndProc,

                                     hWnd,

                                     Message,

                                     wParam,

                                     lParam);

      }

   }

   else return CallWindowProc(lpfnOldWndProc,

                              hWnd,

                              Message,

                              wParam,

                              lParam);

}

STATUS

======

Microsoft has confirmed this to be a problem in the product(s) listed at

the beginning of this article.

This problem does not occur in Chinese or Japenese Windows 95 or Windows

NT.

Additional reference words: cwin jwin fesdk

KBCategory: kbbuglist kbprg

KBSubcategory: WIntlDev


BUG: Winsock--Lost FD_WRITE Notifications

Article ID: Q129974

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1

--------------------------------------------------------------------

SYMPTOMS

========

In both of the following situations, the initial FD_WRITE notifications are

never received:

 - Create a datagram socket and call WSAAsyncSelect() with interest in

   FD_WRITE notification.

   -or-

 - Create a stream socket, call connect() to connect to a TCP server and

   call WSAAsyncSelect() with interest in FD_WRITE notification.

RESOLUTION

==========

In the first case, call the bind() function in addition to the socket()

function as shown:

   SOCKADDR_IN source_sin;

   source_sin.sin_family = AF_INET;

   source_sin.sin_addr.s_addr = htonl(INADDR_ANY);

   source_sin.sin_port = htons(0);

   s = socket(AF_INET, SOCK_DGRAM, 0);

   bind(s, (struct sockaddr FAR *)&source_sin,sizeof(source_sin));

   WSAAsyncSelect(s, hWnd, WSA_WRITE, FD_WRITE);

The window specified by hWnd in WSAAsyncSelect() will now receive the

FD_WRITE notifications properly.

In second case, call socket() and call connect() asynchronously as shown:

   SOCKADDR_IN dest_sin;

   dest_sin.sin_family = AF_INET;

   dest_sin.sin_addr.s_addr = htonl(SERV_HOST_ADDR);

   dest_sin.sin_port = htons(SERVER_TCP_PORT);

   s = socket(AF_INET, SOCK_STREAM, 0);

   WSAAsyncSelect(s, hWnd, WSA_WRITE, FD_CONNECT | FD_WRITE);

   connect(s, (struct sockaddr FAR *)&dest_sin, sizeof(dest_sin);

STATUS

======

Microsoft has confirmed this to be a bug in the products listed at the

beginning of this article. We are researching this bug and will post new

information here in the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

================

If a datagram client is not expecting to receive a response from a server,

it can send data without first binding the datagram socket to a specific

port. According to this behavior, a datagram socket should be able to

receive FD_WRITE notifications after calling socket() and WSAAsyncSelect().

Additional reference words: 3.10 buglist3.10

KBCategory: kbprg networking kbbuglist

KBSubcategory: NtwkWinsock


SAMPLE: Using DLLs to Share Menus and Other Resources

Article ID: Q11352

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

It is possible to create a dynamic-link library (DLL) of shared resources

for use in multiple applications. An example of this can be found in the

Microsoft Software Library.

Download ICONLIB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ICONLIB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ICONLIB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ICONLIB.EXE

MORE INFORMATION

================

Resources may be loaded from Windows DLLs as well as from Windows

applications. The module handle returned by the GetModuleHandle()

function may be used as an "instance handle" for finding, loading,

and locking resources.

The technique illustrated in this example is the use of a DLL as the

repository of all shared icons, menus, dialog boxes, and so on.

Some resources are machine dependent and must be transformed before being

passed to an application. Normally, an application gets a default procedure

during task startup, which transforms any machine-dependent resources.

Libraries are not tasks and thus do not get a default procedure. The

application must install a transformation procedure for a library if it

wants to access machine-dependent resources in the DLL.

Additional reference words: 3.00 3.10 softlib ICONLIB

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: App Demonstrates Modal and Modeless Dialog Boxes

Article ID: Q11958

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

TAB is a sample application that demonstrates the differences between modal

and modeless dialog boxes. It also demonstrates using a dialog box within a

dialog box, changing the text in a push button, tabbing between push

buttons, and disabling a push button. TAB also demonstrates how an

application processes the messages received when the user selects a push

button.

Download TAB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TAB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TAB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TAB.EXE

Additional reference words: 3.00 3.10 softlib TAB.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Demonstration of Adding Menus Dynamically

Article ID: Q24600

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

There are two different methods that can be used to add a pop-up menu

to the menu bar at run time.

The first method is to define a version of the application's main menu

that includes the pop-up. This is done in the resource (RC) file with

any other menus that the application uses. To add the menu to the menu

bar, use the following sequence of code:

   hMenu = LoadMenu(hInst, (LPSTR)"<menu name>");

   SetMenu(hWnd, hMenu);

   DrawMenuBar(hWnd);

The second method creates the pop-up menu dynamically at run time. To

use this method, place the following code in the application:

   hPopup = CreateMenu();

   AppendMenu(hPopup, MF_ENABLED, ID1, (LPSTR)"text 1");

   AppendMenu(hPopup, MF_ENABLED, ID2, (LPSTR)"text 2");

   hMenu = GetMenu(hWnd);

   AppendMenu(hMenu, MF_POPUP, hPopup, (LPSTR)"new pop-up");

   DrawMenuBar(hWnd);

There is a complete example of this dynamic-creation method in the

Microsoft Software Library as ADDMENU.

Download ADDMENU.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ADDMENU.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ADDMENU.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ADDMENU.EXE

Additional reference words: 3.00 3.10 softlib ADDMENU.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: Code to Demonstrate Superclassing Available

Article ID: Q32167

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

There is a sample application available in the Microsoft Software Library

that demonstrates the concept of superclassing control windows.

Superclassing provides the same capabilities as subclassing; however, it

can be much more convenient to use and produces smaller code if there are

multiple controls to be altered in the same fashion.

Download SUPERCLS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SUPERCLS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SUPERCLS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SUPERCLS.EXE

MORE INFORMATION

================

To superclass, create a new class that uses the control window procedure

instead of the default window procedure. This enables the application to

process the appropriate messages and to pass the others along to the

default procedure where the messages will be processed correctly based on

the control type.

To implement superclassing, create a window of the type to superclass.

Query all available information about the control and use this information

when the new window is created, substituting the class name and window

procedure. When this window procedure is called, process the desired

messages and pass the others to the standard control procedure (determined

in the query phase).

By registering a new class, the application can create superclassed

controls using the application resource (RC) file or CreateWindow()

function without any further work, which can eliminate a number of

SetWindowLong() calls if many controls are to be modified in the same

manner.

In the SUPERCLS example, the application creates a new control class called

"SuperEdit", which is identical to a regular edit control but refuses to

accept the "b" character.

Look for the string "SuperEdit" in the .C, .RC, and .DEF files to see the

affected areas of the code.

This example shows superclassed Windows controls. Because the class name

has been changed and the application's instance is used in the class

registration, all controls will be created with this application's DS. This

causes no problems for controls. However, this does not work if an attempt

is made to superclass something other than a control. In that case, it is

desirable to use the application's instance with the class so that it will

be destroyed when the application exits. However, it is necessary to

perform some additional work before the call to CallWindowProc() to set the

DS for the subclassed window procedure. The hInstance passed to

CreateWindow() determines which DS the superclassing procedure uses; to

have the superclassed procedure use a different DS, it is necessary to

change the DS value. For more information, see the notes near the call to

CallWindowProc().

Each edit control created using DialogBox(), CreateDialog(), or through an

RC file normally has its own DS. When the application changes the class

name, the code within Windows that handles edit controls is not activated.

Instead, the control uses the application's DS as if it were created using

CreateWindow(). This does not cause any difficulties except that when the

code for the superclassed edit control calls LocalAlloc(), it consumes

space in the application's local heap. This should not cause problems in

most cases.

Additional reference words: 3.00 3.10 sub class subclass control softlib

SUPERCLS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: MAZE Program from MS Systems Journal Demonstrates DDE

Article ID: Q32931

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

MAZE is a file in the Microsoft Software Library that contains the source

code to an application that demonstrates how to use dynamic data exchange

(DDE) in a Windows-based application.

Download MAZE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MAZE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MAZE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MAZE.EXE

When multiple instances of the MAZE application are started, MAZE draws a

bouncing ball in the client area of one of its instances. MAZE creates a

DDE communications link between instances of the MAZE application and uses

this link to pass the ball to other instances at random. MAZE also creates

a DDE conversation with Excel and passes statistical information about the

ball to Excel.

MAZE demonstrates how to use DDE to pass information between applications

and how to use PeekMessage to allow other applications to run

simultaneously with a process-intensive task.

Additional reference words: 3.00 3.10 softlib MAZE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Expanding the Size of a Dialog Box

Article ID: Q35499

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The EXPAND file in the Software Library demonstrates how to create a dialog

box that expands to provide additional controls when the user clicks on a

button control.

Download EXPAND.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EXPAND.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EXPAND.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EXPAND.EXE

The remainder of this article describes the algorithm demonstrated in

the EXPAND file.

MORE INFORMATION

================

To use an expanding dialog box in an application, perform the

following two preparation steps:

1. Design the entire dialog box and determine what controls will not

   be initially visible.

2. Disable these hidden controls in the dialog box template by

   including the WS_DISABLED style bit. This prevents the TAB key or

   the appropriate mnemonic key from giving the focus to one of the

   hidden controls.

When the user clicks the "expand" button, perform the following five

steps:

1. Disable the expand button using EnableWindow(hWnd, FALSE).

2. Enable the previously hidden controls using EnableWindow(hWnd,

   TRUE).

3. Use SetFocus() to place the focus on the appropriate control.

4. Use the following function to retrieve the current position and

   size of the dialog:

      GetWindowRect(hWndDlg, (LPRECT)&r);

5. Use the following function to expand the dialog to its new size

      MoveWindow(hWndDlg, r.left, r.top, r.right - r.left,

                       (r.bottom - r.top) + change, TRUE);

   where "change" is the difference between the small size and the

   large size.

Note that the MoveWindow() function can be used to expand a window in

any direction.

Additional reference words: 3.00 3.10 softlib EXPAND.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Using a Device Driver to Send Binary Data to a Printer

Article ID: Q35708

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows environment, device ports are a scarce

resource that are shared by all applications running in the system. If

an application is designed to send raw, unformatted data to a device

port, it should use the Windows Print Spooler to ensure that two or

more applications do not use the port at once.

MORE INFORMATION

================

The best method to implement this functionality is by means of a

device driver through which an application can pass data to the port

without change. RAW.EXE is a file in the Microsoft Software Library that

contains the source code to a device driver that implements the

PASSTHROUGH escape function. The RAW printer driver is intended as a

sample driver and has not been designed to be distributed as part of a

commercial application.

Download RAW.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RAW.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RAW.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RAW.EXE

Earlier versions of the RAW driver were incompatible with Adobe Type

Manager (ATM) because ATM requires a printer driver to return a

nonzero value when the driver processes the RealizeObject function.

The current version of RAW has been updated to be compatible with ATM.

Additional reference words: 3.00 3.10 print log softlib RAW.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


SAMPLE: Windows Journal Hooks Sample Source Code

Article ID: Q37138

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

JOURNAL is a file in the Software Library that contains sample code to

demonstrate the use of the journal hooks WH_JOURNALRECORD and

WH_JOURNALPLAYBACK. The JOURNAL archive file contains the source to

APP.EXE; WNDPROC.C is one of the source files.

The APP.EXE application serves only one purpose; it illustrates how to

call the dynamic-link library (DLL) that performs all of the

journaling work. The WNDPROC.C application module contains calls to

the DLL to record and play back messages. One of the source modules

for the DLL, JOURNAL.C, contains all the code required to create

DIARY.BIN, a file of messages. The messages in DIARY.BIN can be played

back at a later time. The DIARY.BIN file is overwritten each time the

user chooses Record On from the menu.

The JOURNAL code can serve as the basis of a "hands off" application

demonstration. The application demonstrating itself can call the high-

level functions in the DLL to play each event.

The DIARY.BIN file is also included in the JOURNAL archive to

demonstrate using journal hooks. To demonstrate playing the contents

of a DIARY.BIN file, select Play from the menu.

Download JOURNAL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for JOURNAL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download JOURNAL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get JOURNAL.EXE

Additional reference words: 3.00 SetWindowsHook 3.10 softlib JOURNAL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrHks


SAMPLE: Using User-Defined Resources in Windows Applications

Article ID: Q37657

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

RCDATA is a file in the Microsoft Software Library that demonstrates using

a user-defined resource in a Windows-based application.

The resource is declared in the resource (RC) file as follows:

   TEST RCDATA

   BEGIN

       <data goes here>

   END

An application accesses this resource with the following statements:

   hFound = FindResource(hInstance, "TEST", RT_RCDATA);

   hRes = LoadResource(hInstance, hFound);

   lpBuff = LockResource(hRes);

   // use lpBuff to access the resource contents

   bResult = UnlockResource(hRes);

   bResult = FreeResource(hRes);

Download RCDATA.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RCDATA.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RCDATA.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RCDATA.EXE

Additional reference words: 3.00 3.10 softlib RCDATA.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrRsc


SAMPLE: Using Main Window Edit Menu w/ Dialog Box Edit Control

Article ID: Q38170

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When a dialog box has an edit control, it may be helpful if the commands

from the Edit menu on the application's main window can be used to change

the text. The following factors must be considered when this is done:

 - Where does the input focus go when the editing operation is complete?

 - What happens if no text is selected when Cut, Copy, or Clear is chosen?

 - If more than one edit control is visible, on which control should the

   action be taken?

When the main window receives a command from its Edit menu, the

corresponding command is sent to the appropriate edit control.

CREATDLG is a file in the Microsoft Software Library that demonstrates this

procedure. The code is commented, and a README.TXT file that discusses

coding issues is included.

Download CREATDLG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S12127.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CREATDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CREATDLG.EXE

Additional reference words: 3.00 3.10 softlib CREATDLG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Aligning the Logical and Physical Coordinate Systems

Article ID: Q39090

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The text below explains how to use the following functions in the Microsoft

Windows operating system: SetViewportExt(), SetViewportOrg(),

SetWindowExt(), and SetWindowOrg(). The explanation is based on the SHAPES

sample application that was provided with the Microsoft Windows SDK

versions 2.x. A version of this sample for Windows 3.0 and later is

available in the Microsoft Software Library.

Download SHAPES.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SHAPES.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SHAPES.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SHAPES.EXE

MORE INFORMATION

================

An application uses the SetViewportExt(), SetViewportOrg(), SetWindowExt(),

and SetWindowOrg() to align the two separate coordinate systems that the

Windows graphics device interface (GDI) provides. SetWindowOrg() and

SetViewportOrg() provide a one-to-one mapping of the two specified origin

points (one in each coordinate system). The SetWindowExt() and

SetViewportExt() functions instruct GDI how much to stretch (or compress)

the coordinate system after mapping the two specified points to each other.

The following code, drawn from the SHAPES sample, maps point (-10,

110) in the logical coordinate system to point (0, 0) in the client

coordinate system. Then the code sets the width of the viewport to 120

logical units and the height of the viewport to -120 logical units.

   RECT ClientRect;

   GetClientRect(hDC, ClientRect);

   SetWindowOrg(hDC, -10, 110);

   SetViewportOrg(hDC, 0, 0);

   SetWindowExt(hDC, 120, -120);

   SetViewportExt(hDC,

                  (short)(ClientRect.right - ClientRect.left),

                  (short)(ClientRect.bottom - ClientRect.top));

Negative coordinate scaling is required because the specified origin

point is above the displayed image. These concepts are perhaps best

illustrated on graph paper. Consider the following example. In the

logical coordinate system, an image of a star starts in the upper-left

quadrant of the coordinate system, between (-10, 110) and (110, -10).

Mark the specified origin (-10, 110) on the graph paper. To include

the image of the star in the viewport, the viewport "extent" must

include 120 units to the right (positive x direction) and 120 units

down (negative y direction). The specified viewport extents provide

the required viewport.

In the example, the left and top members of the ClientRect data

structure are always zero. The subtraction is unnecessary but included

to demonstrate how the application aligns the rectangles in the

logical and client coordinate systems.

To reduce the size of the star, reduce the size of the viewport by

reducing the size of the arguments to SetViewportExt(), or increase the

amount of logical area mapped into the viewport by increasing the

arguments to SetWindowExt().

The easiest method of becoming familiar with these functions is to

change only one argument value at a time, and change it by only a

small amount. For example, start by changing the code above to include

the following:

   SetWindowOrg(hDC, -30, 110);

Changing the window origin in this manner trims some of the right side

of the star from the screen. Change the window origin back to its

original location, then change other values. You may need to change

the viewport coordinates by a larger amount than the window

coordinates to see the changes.

Changing one coordinate at a time is effective only in the

MM_ANISOTROPIC mapping mode, which allows the units in the coordinate

system to be rectangular rather than square. An application can change

units on the y-axis without changing the x-axis, and vice versa. In

contrast, the MM_ISOTROPIC mapping mode enforces square units, with an

equivalent measure along each axis.

Additional reference words: 3.00 3.10 softlib SHAPES.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiDc


SAMPLE: Multiple Application Instance Data in a DLL

Article ID: Q40962

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

DLLINST is a file in the Microsoft Software Library that demonstrates how a

dynamic-link library (DLL) can interact with more than one application

at a time with each interaction independent from the others. To

illustrate the independence of each interaction, the DLL maintains

separate data for each application instance. This article discusses

the techniques used in DLLINST.

MORE INFORMATION

================

When a DLL receives a call from an application, nothing in the call

specifies the application instance involved. Because instance

information is required to ensure that each interaction is

independent, the application's instance is one of the parameters for

the interface functions provided by the DLL.

If the DLL contains global data that are used by each application

instance, the following techniques help avoid data access conflicts:

1. Use a flag as a mutual-exclusion semaphore. This will ensure that

   only one application instance can use the DLL at any given time.

2. Use additional storage in the DLL to provide each application

   instance with its own data area. One way to implement this is

   through a list of records that is indexed by the instance.

DLLINST is a sample application in the Microsoft Software Library that

demonstrates the technique of tracking the identity of the calling

application. The DLL provides a primitive string edit functionality

within a dialog box, and keeps separate buffers indexed by the

application instance for each open dialog.

Download DLLINST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLLINST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLLINST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLLINST.EXE

The DLLINST file contains the source code to two modules, DLLINST.EXE

and DLGDLL.DLL. The DLGDLL file implements the second technique listed

above: instanced data for each calling application.

Multiple instances of the DLLINST application can call into the DLGDLL

DLL to demonstrate the techniques.

Note that the application passes hInst (the application's instance

handle) to the DLL through the call to the TestDLLDlg function in

MainWndProc.

As an alternative, the DLL can call the GetCurrentTask function to

determine which instance is calling. This eliminates the requirement

that hInst be passed in. If the DLL uses hWnd, the DLL can maintain a

separate data area for each window rather than for each instance. This

technique might be useful for a Multiple Document Interface (MDI)

application.

DLLINST "unregisters" each application before it returns, which frees

the buffer for use by another instance. This prevents data from

persisting across calls to the DLL. Although the DLL can recognize and

register a new instance that calls the DLL for the first time, to

implement persistent data, each instance must call a cleanup function

in the DLL before terminating. This prevents a possible problem where

an instance terminates and its handle is reused by a new instance.

In Windows version 3.1, the TOOLHELP DLL provides the NFY_EXITTASK

notification to inform a callback function that a task terminated.

The DLL can use this to unregister an application, even if it

terminated abnormally. The callback function can use the

GetCurrentTask and TaskFindHandle functions to determine if the

terminating task has called  the DLL.

The following relevant function is in the DLLINST.C file:

MainWndProc    Processes messages for the application. Calls the

               TestDLLDlg function in DLGDLL to display a dialog box

               that edits data for a calling instance.

The following relevant functions are in the DLGDLL.C file:

DlgProc        Processes messages for DLL dialog box and writes

               DlgItemText to the correct buffer.

TestDLLDlg     Called by each instance of the application to display a

               dialog box.

Additional reference words: 3.00 3.10 softlib DLLINST.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: Code to Access New .EXE File Headers

Article ID: Q42061

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

DUMPDESC is a file in the Microsoft Software Library that demonstrates

reading the description line from an EXE file. During the processing of the

WM_PAINT message, the program reads its own description line and displays

the contents in its client area.

The most relevant portion of the code is in the DumpDescPaint() function.

Download DUMPDESC.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DUMPDESC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DUMPDESC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DUMPDESC.EXE

Additional reference words: 3.00 3.10 softlib DUMPDESC.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrFmt


SAMPLE: Creating a User-Defined Control

Article ID: Q43492

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0

----------------------------------------------------------------------

SUMMARY

=======

USERCTL.EXE is a file in the Software Library that demonstrates how to

create and use a custom control. The file contains a modification of

the Windows 2 Software Development Kit (SDK) HELLO program and

SPECTRUM, a source code example of a custom control.

Download USERCTL.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for USERCTL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download USERCTL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get USERCTL.EXE

Additional reference words: 3.00 softlib USERCTL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Sharing Global Memory Between Applications

Article ID: Q47499

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

TALK is a sample application in the Microsoft Software Library that

demonstrates how to share data between two applications without having

to use dynamic data exchange (DDE). TALK contains two applications

(POST and HELLO) that demonstrate three different ways to pass

information between two applications. Please note that either the

GMEM_DDESHARE or the GMEM_NOTBANKED flag must be specified when the

memory is allocated. This ensures that the memory referenced by the

handle is available even when Windows is running in real mode and EMS

memory is in use.

Download TALK.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TALK.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TALK.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TALK.EXE

NOTE: Although the principles of message-based DDE communication shown in

the TALK sample are compatible with Windows 3.1, Microsoft strongly

recommends that new applications for Windows 3.1 and later use the DDEML

library provided by the system.

Additional reference words: 3.00 3.10 softlib TALK.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Creating the Default Border Around a Push Button

Article ID: Q48713

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

There is a file named DEFBTN in the Microsoft Software Library that

demonstrates

the correct message sequence to change the status of a push button from the

"normal" state to the "default" state. The default push button receives a

message when the ENTER key is choosen in a dialog box, no matter which

control currently has the focus.

In the DEFBTN example, when a numeral button is pressed ("1", "2", or "3")

the corresponding number button ("one", "two", or "three") becomes the

default button.

Download DEFBTN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DEFBTN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DEFBTN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DEFBTN.EXE

For a button to be correctly activated by using an accelerator, it is

necessary to subclass the button to process the focus messages. This is

caused by the fact that accelerators bypass some steps in the message flow.

Additional reference words: 3.00 3.10 softlib DEFBTN.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: QuickSort Sample Code for Windows

Article ID: Q64077

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

QSRTWIN is a file in the Microsoft Software Library that demonstrates using

the qsort() function in the C run-time library in an application.

Download QSRTWIN.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for QSRTWIN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download QSRTWIN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get QSRTWIN.EXE

Additional reference words: 3.00 3.10 softlib QSRTWIN.EXE

KBCategory: kbprg kbfile

KBSubcategory: TlsMisc


SAMPLE: Right Justifying Numbers in a Windows List Box

Article ID: Q64078

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In versions of Windows earlier than 3.0, it is possible to align columns of

information in a list box with spaces because all characters in the system

font are the same width. In Windows 3.0, the system font is proportionally

spaced with letters of differing widths, which prevents this technique from

being usable.

Tabs can be used to align columns in a list box. The LBS_USETABSTOPS style

must be specified when the list box is created. Then, set a tab to

correspond with the position of each character of each numeric column. The

tabs are specified in dialog units, which are one-fourth of a character

width. For example, a three-digit field that should align 12 characters

from the left edge of the dialog box can be implemented by setting tabs at

positions 40, 44, and 48. This is illustrated below:

    +------------+

    |text     xxx|

    |longer    xx|

              ^^^

              ||+- position 48

              |+-- position 44

              +--- position 40

After determining the text to insert in the list box, convert the spaces to

the appropriate number of tabs as the following code fragment demonstrates:

   sprintf(szNumBuffer, "%3d", Number);

   for (i = 0; i < 3; i++)

     if (szNumBuffer[i] == ' ')

        szNumBuffer[i] = '\t';

This code uses the three tabs set above.

There is a file in the Microsoft Software Library named RIGHTJUS that

illustrates this convention.

NOTE: This sample is applicable only to Windows 3.1, NOT to Win32.

Download RIGHTJUS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RIGHTJUS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RIGHTJUS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RIGHTJUS.EXE

Additional reference words: 3.00 3.10 softlib RIGHTJUS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Owner-Draw: Processing WM_DRAWITEM to Draw Controls

Article ID: Q64326

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

At the heart of owner-draw controls is the processing of WM_DRAWITEM

messages. A WM_DRAWITEM message is generated in response to an action by

the user. When an application processes this message, it paints a button, a

menu, a list box item, or a combo box item. The application must perform

the drawing of the specified control or item because the application is

free to give the control any appearance; Windows does not interfere in the

processing of owner-draw controls.

ODLIST is a file in the Microsoft Software Library that contains a sample

application that demonstrates processing the WM_DRAWITEM message.

NOTE: This sample is applicable to Windows 3.1 only, NOT to Win32.

Download ODLIST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ODLIST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ODLIST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ODLIST.EXE

MORE INFORMATION

================

The lParam that accompanies the WM_DRAWITEM message is a long (or far)

segment:offset pointer to a DRAWITEMSTRUCT data structure. For convenience

in accessing the members of the structure, the lParam is usually assigned

to a LPDRAWITEMSTRUCT variable called "lpdis" as in the following example:

   ...

   LPDRAWITEMSTRUCT lpdis;

   ...

   switch (message)

      {

   case WM_DRAWITEM:

      lpdis = (LPDRAWITEMSTRUCT)lParam;

   ...

After handling the WM_DRAWITEM message, Windows can move the

DRAWITEMSTRUCT in memory. This movement may occur even if the

application's code and data segments are FIXED. Therefore, do not keep

and reuse the value of the lpdis variable to process later WM_DRAWITEM

messages, because the far pointer may no longer be valid. Each

WM_DRAWITEM message will be accompanied by a valid lParam, which the

application should use.

An owner-draw control can be created as the child of a dialog box or of a

pop-up or overlapped window. The parent dialog box or window procedure will

receive a separate WM_DRAWITEM message for each owner- draw button and for

each visible item in other controls. This message is sent under any of the

following four circumstances:

1. When each item is first drawn

2. When each item is redrawn

3. When each item's selection state changes (selected or deselected)

4. When each item's focus state changes (receives or loses the focus)

For a list box with numerous visible items, Windows will send a substantial

number of WM_DRAWITEM messages. Therefore, it is good practice to be as

time efficient as possible when processing these messages.

During the processing of a WM_DRAWITEM message, be careful not to call a

function such as MessageBox() that might draw over the control. Violating

this caution may cause Windows to become unstable.

The members of the DRAWITEMSTRUCT data structure, documented on pages 7-36

to 7-38 of the "Microsoft Windows SDK Programmer's Reference Volume 2,"

indicate which item in which control should be drawn, and what the status

of that item is. Generally, a control item is drawn differently when it has

the focus, or when it is selected, than when it has neither of these

attributes.

Application code should be prepared to perform three actions. The

"itemAction" field of the DRAWITEMSTRUCT indicates the proper action to

take. The values of the itemAction field are as follows:

   Value             Description

   -----             -----------

   ODA_FOCUS         The item's focus state has changed (gained or lost

                     the focus) since it was last drawn.

   ODA_SELECT        The item's selection state has changed (selected or

                     unselected) since it was last drawn.

   ODA_DRAWENTIRE    The item has not been changed. This is a request to

                     the application to redraw the item without

                     change. The "itemState" bits, described below,

                     specify the attributes that the item should have.

In addition to the three actions above, there are several states in which

each control may exist. These states are indicated by the "itemState" field

of the DRAWITEMSTRUCT. The two states discussed here are the most typical

and are the only states discussed in this article. The other states may be

handled in a similar manner. The discussed values of the itemState field

are as follows:

   Value             Description

   -----             -----------

   ODS_FOCUS         The item has the input focus.

   ODS_SELECTED      The item is selected.

If neither of these bits is set, the control or item is in its

"normal" state.

The most frequently encountered case is to have itemAction equal to

ODA_DRAWENTIRE and neither of the monitored ODS_* bits set. If the data to

be displayed is a string of text, call TextOut() or TabbedTextOut() to draw

the text on the screen. Nontext data can be displayed with GDI functions

such as BitBlt() or Rectangle(). An application can combine these functions

as appropriate.

Identifying String vs. Nonstring Items

---------------------------------------

As discussed above, each WM_DRAWITEM message is accompanied by a far

pointer to a DRAWITEMSTRUCT. For owner-draw list boxes created with the

LBS_HASSTRINGS style, and for owner-draw combo boxes that have been created

with both the CBS_HASSTRINGS and CBS_DROPDOWNLIST styles, the itemID field

in this structure will be an index that refers to the appropriate string.

The itemData field will NOT be a far pointer to the string. To retrieve a

pointer to the string, send a message to the list box or combo box. The

wParam of the message is set to the itemID from the structure. The

following code assumes that the list box or combo box in question is in a

dialog box:

   LPSTR lpItem;

To a list box:

   lpItem = SendDlgItemMessage(hDlg, LBID, LB_GETTEXT,

                                     lpdis->itemID, 0L);

To a combo box:

   lpItem = SendDlgItemMessage(hDlg, CBID, CB_GETLBTEXT,

                                     lpdis->itemID, 0L);

LBID and CBID are the integer identifiers of the list box and combo

box, respectively, within the dialog box.

If the list box or combo box does not have one of the styles described

above, the 32-bit itemData field provides information to identify the

item.

Message Traffic for an Item with Both Selection and Focus

---------------------------------------------------------

An application will receive two WM_DRAWITEM messages for an item that is

both selected and has the focus.

For example, for an item in a single-selection list box that has the focus

and is selected, the application will first receive a WM_DRAWITEM message

with the ODA_DRAWENTIRE or ODA_SELECT action and the ODS_SELECTED state.

Then, the application will receive a second WM_DRAWITEM message with the

ODA_DRAWENTIRE or ODA_FOCUS action and the ODS_FOCUS state. Therefore, it

is important to handle the selection state separately from the focus state.

Handling the two attributes individually is especially important because

some functions, such as DrawFocusRect(), remove the effect of one call with

a second call. DrawFocusRect() creates the dashed rectangle border around

the text of a control with the focus.

A problem occurs when DrawFocusRect() is called during the processing of a

selection state message to draw the focus rectangle. If DrawFocusRect() is

called again during the processing of the focus state message, the

rectangle is removed, which is highly undesirable.

In Windows 3.0, if at the end of processing the WM_DRAWITEM message with

ODS_FOCUS set, the dialog box procedure returns FALSE, the Dialog Manager

code will call DrawFocusRect(). This call may serve as a safety feature in

the application, or it may introduce a problem. However, this undocumented

behavior may change in future versions of Windows and is not guaranteed.

Three points in summary:

1. The focus state should be handled separately from the selection

   state.

2. The application must do all necessary drawing itself.

3. The dialog procedure returns TRUE when processing is finished.

A Combo Box's Drop-Down List Box Does Not Receive the Focus

-----------------------------------------------------------

Only the static area of a CBS_DROPDOWNLIST owner-draw combo box will

receive the focus action or state; the dropped-down list box does not

receive the focus.

The static text area, which displays the selected list box item, is part of

the parent combo box window. Indicate that the combo box has received the

focus by drawing the static area appropriately. The static area can be

identified by its itemID of -1 (0xffff). The static area can also be

identified by the fact that its left side, rcItem.left, is intentionally

greater than zero to offset the selected item to the right a few pixels,

but the left side of the list box items are zero.

The list box is a child window of the combo box. List box items can receive

the selection action or state when they are actually selected, and also

when they are scrolled over with the mouse cursor or with the keyboard.

Upon receipt of the WM_DRAWITEM message, draw the currently selected item

appropriately.

Reusing Code for Equivalent Combinations of Actions and States

--------------------------------------------------------------

During the design phase for the application, both the actions and states

should be considered. To save work, note that some action/state

combinations are effectively equivalent. Equivalent states should result in

the item being drawn the same way, typically by a call to a function in the

application.

An example of common equivalent action/state combinations is ODA_DRAWENTIRE

and ODS_FOCUS versus ODA_FOCUS and ODS_FOCUS. In either case, the

application would draw the control in its focus state. Similarly,

ODA_DRAWENTIRE and ODS_SELECTED versus ODA_SELECT with ODS_SELECTED causes

the control to be drawn in its selected state.

A common method for processing owner-draw items is to draw the control in

its "normal" state, modify the display of the control based on its

selection state, and then modify the display of the control based upon its

focus state, as appropriate.

Below is an example of the common method. The following code fragment could

be inserted into the dialog box procedure of a dialog box that contains an

owner-draw list box with the LBS_HASSTRINGS style. This code processes the

WM_DRAWITEM and WM_MEASUREITEM messages:

/********************************************************************

 *     O W N E R - D R A W   M E S S A G E   P R O C E S S I N G    *

 *                                                                  *

 * Do all drawing for owner-draw list box string items.             *

 * Return TRUE when drawing completed.                              *

 * Or else break and return FALSE to do nothing.                    *

 ********************************************************************/

  LPDRAWITEMSTRUCT    lpdis;     // pointer for drawing struct

  LPMEASUREITEMSTRUCT lpmis;     // pointer for item measurement

  HDC                 hDC;       // dialog's device context

  TEXTMETRIC          tm;        // for system font height

  char                szBuf[80]; // buffer for list box string

  :

  :

  switch (message)

     {

  case WM_DRAWITEM:

     /* Get convenient pointer to the DRAWITEMSTRUCT */

     lpdis = (LPDRAWITEMSTRUCT)lParam;

     /*

      * If no items in list box yet, or combo box's static area have

      * the focus, indicate focus for specified rectangle.

      */

      if (lpdis->itemID == -1)

         {

         HandleFocusState(lpdis);    // function below

         return TRUE;

         }

     /*

      * Draw a list box item in its normal state. Then check if it is

      * selected or has the focus state, and call functions to handle

      * drawing for these states if necessary.

      */

     if (lpdis->itemAction & ODA_DRAWENTIRE)

        {

        /* Get text of string referred to by itemID */

        SendMessage(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,

                    (LONG)(LPSTR)szBuf);

        /*

         * If the items were not strings, lpdis->itemData provides

         * a 32-bit index to identify the item.

         */

        // call TextOut or TabbedTextOut to display "szBuf"

        :

        :

        // If item selected, do additional drawing  -- invert rect

        if (lpdis->itemState & ODS_SELECTED)

           HandleSelectionState(lpdis);  // function below

        // if item has focus, do additional drawing -- dashed border

        if (lpdis->itemState & ODS_FOCUS)

           HandleFocusState(lpdis);

        return TRUE;

        } // lpdis->itemAction & ODA_DRAWENTIRE

     /*

      * If a list box item was just selected or unselected, call

      * function (which could check if ODS_SELECTED bit is set) and

      * draw item in selected or unselected state.

      */

     if (lpdis->itemAction & ODA_SELECT)

        {

        HandleSelectionState(lpdis);

        return TRUE;

        }

     /*

      * If a list box item just gained or lost the focus, call

      * function (which could check if ODS_FOCUS bit is set) and draw

      * item in its focus or nonfocus state.

      */

     if (lpdis->itemAction & ODA_FOCUS)

        {

        HandleFocusState(lpdis);

        return TRUE;

        }

     break; // case WM_DRAWITEM

  /* Must specify owner-draw list box item height. */

  case WM_MEASUREITEM:

     lpmis = (LPMEASUREITEMSTRUCT)lParam;  /* for convenience      */

     /* get and use height of system font for drawing */

     hDC = GetDC(hDlg);                 /* get device context     */

     GetTextMetrics(hDC, &tm);          /* get text information   */

     lpmis->itemHeight = tm.tmHeight;   /* required to set height */

     ReleaseDC(hDlg, hDC);              /* release device context */

     break;

     :

     :

     } // switch

  return FALSE;

}

/********************************************************************

 *  FUNCTION   : HandleSelectionState(LPDRAWITEMSTRUCT)             *

 *                                                                  *

 *  PURPOSE    : Handles selection of list box item                 *

 ********************************************************************/

void HandleSelectionState(LPDRAWITEMSTRUCT lpdis)

{

/*

 * This function could test the ODS_SELECTED bit in the itemState

 * field. If true, draw the selected state, otherwise draw the non-

 * selected state. However, because a second call to InvertRect()

 * restores the rectangle to its original state, make the call whether

 * the item is selected or unselected.

 */

    InvertRect(lpdis->hDC, (LPRECT)&lpdis->rcItem);

}

/********************************************************************

 *  FUNCTION   : HandleFocusState(LPDRAWITEMSTRUCT)                 *

 *                                                                  *

 *  PURPOSE    : Handles focus state of list box item               *

 ********************************************************************/

void HandleFocusState(LPDRAWITEMSTRUCT lpdis)

{

/*

 * This function could test the ODS_FOCUS bit in the itemState field.

 * If true, draw the selected state, otherwise draw the non-selected

 * state. However, because a second call to DrawFocusRect() restores

 * the rectangle to its original state, make the call whether the item

 * has the focus or not.

 */

    // New to Windows 3.0, this function draws a black dashed line

    // on the border of the specified rectangle

    DrawFocusRect(lpdis->hDC, (LPRECT) &lpdis->rcItem);

}

Additional reference words: 3.00 3.10 softlib ODLIST.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Owner-Draw: 3-D Push Button Made from Bitmaps with Text

Article ID: Q64328

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

An owner-draw button can be defined and drawn to provide any desired

appearance, even to mimic the three-dimensional push buttons of Windows

version 3.0. With an owner-draw button, the application can control the

button face color, unlike a standard push button, which always has a gray

face.

MORE INFORMATION

================

ODBUTTON is a file in the Microsoft Software Library that contains an

example of an owner-draw button. The button uses two 64-by-64-bit bitmaps.

The first bitmap represents the default button state. In this state, the

button has a light gray face, a light left and upper border, and the

button's text is centered in the bitmap. The second bitmap represents the

pressed button state. In this state, the button has a solid, dark gray

face, and the button's text is shifted to the right and down two pixels.

Download ODBUTTON.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ODBUTTON.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ODBUTTON.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ODBUTTON.EXE

The ODBUTTON sample source code can be used as a template for creating

other applications. The main task involves creating appropriate

bitmaps.

Under Windows 2.x, an application can change the color of the button face

by processing WM_CTLCOLOR messages. This functionality is not available in

Windows 3.0. However, the more powerful owner-draw feature can be used to

achieve the same effect.

Like a Windows 3.0 standard push button, this sample owner-draw button

indicates that it has the focus by drawing a dashed, black rectangular

border around the button text. This is accomplished by using the new

Windows 3.0 function, DrawFocusRect(). Like the text of the button, the

focus rectangle must also be shifted right and down two pixels when the

button is pressed.

Bitmaps are created in a fixed size, in pixels, regardless of the display

resolution used. An application can determine which display is in use by

reading the SYSTEM.INI file. Two alternatives are available to create

buttons that are an appropriate size on different displays, as follows:

1. Create different pairs of default/pressed bitmaps for each display

   resolution the application is targeted (for example, Hercules

   monochrome, CGA, EGA, VGA, super VGA, and 8514).

2. Create separate bitmaps for the borders of the button and for the

   button faces. During the initialization of the application, make

   four calls to StretchBlt(). The first call should modify the left

   and right borders vertically. The second call should change the top

   and bottom borders horizontally. The third and fourth calls should

   modify each button face bitmap both horizontally and vertically.

   Doing separate calls eliminates distortion to the border widths as

   a display-specific bitmap is created.

Apart from the information discussed above, owner-draw buttons are handled

like other owner-draw controls. However, Windows does not send the

application a WM_MEASUREITEM message to define the dimensions of the button

control dynamically. The dimensions of the owner-draw button are specified

in a dialog box template or CreateWindow() call, similar to the dimensions

of nonowner-draw buttons.

Like other owner-draw controls, the application draws the owner-draw

button in response to a WM_DRAWITEM message. Drawing should take into

account the selection and focus states of the control, as well as the

normal state without either selection or focus.

Additional reference words: 3.00 3.10 softlib ODBUTTON.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Right and Decimal-Alignment in Owner-Draw Controls

Article ID: Q65792

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows graphical environment, the primary feature of an

owner-draw control is the ability to customize the manner that a control

displays information and to extend its capabilities. An example of a

customized presentation is to decimal align a column of numbers in an owner-

draw list box. This article describes how to perform this alignment, and

then describes some example code in the Microsoft Software Library.

ODLIST2 is a file in the Microsoft Software Library that demonstrates this

method to right align a substring of digits. The ODLIST2 application

implements a horizontally scrollable list box that contains a small

database of account records. The titles of the "Account", "Balance",

and "Name" fields scroll with their associated column data because the

application subclasses the main database list box to process

WM_HSCROLL messages. When a scroll message is received by the data

list box, it sends a corresponding WM_HSCROLL message to the title

list box.

Download ODLIST2.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ODLIST2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ODLIST2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ODLIST2.EXE

MORE INFORMATION

================

To right align a string (of digits or of text) at a particular horizontal

position "X," the application must compute the length of the string. Then,

move that distance to the left of "X" before drawing the string. The width

of a string is contained in the low-order word of the value returned by the

GetTextExtent() or GetTabbedTextExtent() functions.

For example, if the following are true

   X         is the horizontal position for the right edge of the

                text

   hDC       is a handle to a device context

   szDigits  is an array of characters

the right-aligned text would be drawn starting at the following

position:

   X - LOWORD(GetTextExtent(hDC, szDigits, lstrlen(szDigits))

Because digit characters have equal widths, aligning the right side of the

digit strings in an owner-draw list box to the same horizontal position

keeps all the columns lined up. If the decimal point is located

consistently, as for dollars and cents, the numbers are easily aligned. For

example:

     123.45

    6543.12

One technique to right align substrings is to use multiple calls to

the TextOut function when drawing each list box item. Calculate the

origin of each substring as follows:

   (the desired right position) - (the width of the substring)

Another way to right align a string or substring of digits is to use

tab stops. A tab can be defined so that its position, plus the width

of the digit string, is equal to the desired right position "X."

The code sample below implements a tab stop before a digit substring.

To use this code, place it into the code that processes the

WM_DRAWITEM message for an owner-draw list box with the

LBS_USETABSTOPS style:

   nWidth     is the width (x-extent) of the digit substring.

   lpdis      is the far pointer to a DRAWITEMSTRUCT obtained as the

                 lParam in a WM_DRAWITEM message.

   nTabStops  is an integer array of tab stops. If the current mapping

                 mode is MM_TEXT, the values in the array are in

                 pixels.

   // Get the x extent of digit substring

   nWidth = LOWORD(GetTextExtent(lpdis->hDC, szDigits,

                lstrlen(szDigits)));

   // Set first tab stop to align the right side of the digit

   // substring with the right border of the list box

   nTabStops[0] = X - nWidth;

   // Draw digit string at tabbed position

   TabbedTextOut(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,

        (LPSTR)szDigits, lstrlen(szDigits), 1, (LPINT)nTabStops);

Additional reference words: 3.00 3.10 listbox softlib ODLIST2.EXE

KBCategory: kbprg kbfile kbcode

KBSubcategory: UsrCtl


SAMPLE: Placing a Status Bar in an MDI Frame Window

Article ID: Q65880

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Many applications that employ the Windows multiple document interface

(MDI) provide information to the user through the use of a status bar

at the bottom of the application. Microsoft Excel and Microsoft Word

for Windows are two examples of applications that provide this

context-sensitive assistance.

To create a status bar at the bottom of an MDI frame window, do the

following:

1. Create an appropriately sized child of the frame window to display

   the status information.

2. Size the MDI client window so that it does not obscure the status

   window.

When the frame window changes size, it is necessary to size the MDI

client and status windows so that the status bar will remain visible.

There is a sample application in the Microsoft Software Library named

MDISTAT that demonstrates how to implement a status bar within an MDI

application.

Download MDISTAT.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MDISTAT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MDISTAT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MDISTAT.EXE

Additional reference words: 3.00 3.10 softlib MDISTAT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Using RegisterWindowMessage for Interapp Communication

Article ID: Q66246

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The RegisterWindowMessage() function associates a unique message

number with a given message name. This message number is guaranteed to

be unique throughout the system but may change between Windows

sessions. The new message is typically used for communication between

two cooperating applications.

Using RegisterWindowMessage() is an alternative to using DDE to

communicate between two or more applications. This technique is most

useful if the information to be passed between applications can be

contained in the wParam and/or lParam parameter of the message.

A sample application is available that demonstrates how to implement

communication between two cooperating applications, using

RegisterWindowMessage().

Download TWINS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TWINS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TWINS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TWINS.EXE

Additional reference words: 3.00 3.10 softlib TWINS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMsg


SAMPLE: MENUITEMTEMPLATE Structure Is Documented Incorrectly

Article ID: Q66247

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The MENUITEMTEMPLATE structure is found in WINDOWS.H, which declares the

structure as follows:

   typedef struct

       {

       WORD    mtOption;

       WORD    mtID;

       char    mtString[1];

       } MENUITEMTEMPLATE;

Single-item arrays, such as mtString, provide a named field to use to

access memory. The actual text of the string is stored in the structure,

not a pointer to text stored elsewhere.

MORE INFORMATION

================

MENUTEMP is a sample program in the Microsoft Software Library that

demonstrates using the MENUITEMTEMPLATE structure and the

LoadMenuIndirect() function.

Download MENUTEMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MENUTEMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MENUTEMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MENUTEMP.EXE

The declaration of MENUITEMTEMPLATE in WINDOWS.H from the Windows SDK

version 3.1 is correct. If a program attempts to assign an LPSTR to

mtString, the C compiler generates an error. Listed below is an erroneous

code sample:

   MENUITEMTEMPLATE    mit;

   LPSTR               lpch;

   ...

   mit.mtString = lpch;

   ...

The mtString field is a 1-byte placeholder for the array. Because a LPSTR

is 4 bytes long, it cannot be assigned to a 1-byte quantity.

The mtString[1] declaration in the structure serves as a placeholder for an

arbitrary number of characters. An application that uses the

MENUITEMTEMPLATE structure must allocate memory both for the template

itself and the string that is copied into mtString.

The following code sample demonstrates how an application might create a

MENUITEMTEMPLATE structure for a checked menu item having an ID value of

100 and "&Menuitem" as its text:

   HANDLE              hMem;

   LPMENUITEMTEMPLATE  lpmit;

   static char         szMenuItem[] = "&Menuitem";

   ...

   // Note that the single char in the MENUITEMTEMPLATE structure

   // provides space for the null terminator on the string.

   hMem = LocalAlloc(LMEM_MOVEABLE, sizeof(MENUITEMTEMPLATE)

                                       + lstrlen(szMenuItem));

   // LocalLock function returns a near pointer;

   // no problem casting to a far pointer

   lpmit = (LPMENUITEMTEMPLATE)LocalLock(hMem);

   // Set the ID and the checked flag.

   lpmit->mtOption = MF_CHECKED;

   lpmit->mtID = 100;

   // Copy the menu item text.

   lstrcpy(lpmit->mtString, szMenuItem);

   ...

   // Make the following call, when a pointer is no longer needed.

   LocalUnlock(hMem);

   ...

   // Make the following call, when the MENUITEMTEMPLATE

   // is no longer needed.

   LocalFree(hMem);

   ...

Additional reference words: 3.00 3.10 softlib docerr MENUTEMP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: Controlling the Horizontal Scroll Bar on a List Box

Article ID: Q66370

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

This article discusses everything that is required to fully control the

horizontal scroll bar on a list box. This information is also available in

TIPS.HLP which included with Microsoft Visual C/C++. The following is an

outline of the information presented in this article:

A. Windows support for a horizontal scroll bar on a list box

   1. Overview

   2. Software Library sample code

B. New list box messages: LB_SETHORIZONTALEXTENT and

   LB_GETHORIZONTALEXTENT

   1. Default setting for extents is zero.

   2. Messages only change internal value -- do not affect the

      visibility of the scroll bar.

C. Making the scroll bar visible when adding or inserting a string

   1. Must change extent before adding a string.

   2. Must redraw the list box after adding a string.

D. Hiding the scroll bar when deleting a string

   1. Must change the extent before deleting a string.

   2. Must redraw the list box after deleting a string.

   3. Send WM_HSCROLL message with SB_TOP parameter to scroll the list

      box to the left in case it is scrolled right.

   4. Special Handling is needed for LB_RESETCONTENT.

E. Calculating horizontal pixel extents of strings

   1. Use GetTextExtent function.

   2. Font considerations: use WM_GETFONT message.

   3. Use GetTextMetrics and add one tmAveCharWidth.

F. Maintenance of all extents in list box

G. Sample code

   1. Support functions as an additional C file -- static linking to

      application.

   2. Support functions in a DLL, multiple list boxes supported.

MORE INFORMATION

================

Windows Support for Horizontal Scroll Bar in a List Box

-------------------------------------------------------

Microsoft Windows version 3.0 is the first version that recognizes the

WS_HSCROLL window style for list boxes. This style adds a horizontal scroll

bar to the list box. However, the scroll bar does not appear automatically

when a string that is too long to display in a list box is added to that

list box. Similarly, when the last string longer than the list box is

removed, Windows will not hide the scroll bar. This behavior is different

from that of the vertical scroll bar of a list box, which is added and

removed as needed.

An application must maintain the width, in pixels, of each string in the

list box. The LB_SETHORIZONTALEXTENT list box message controls both the

scrolling range and the visibility of a horizontal scroll bar. In this

article, the term "extent" is defined to be the width of an object in

screen pixels. Each string has an extent as does the list box itself.

The other sections of this article provide more detailed information about

special considerations that must occur when dealing with horizontal scroll

bars in list boxes.

There are two files in the Microsoft Software Library that demonstrate the

points made in this article. Each file contains a set of horizontal scroll

bar support functions that maintain the extents of all strings in the list

box and change the scrollable list box extent as required. Additional

details on these samples are found in the "Sample Code" section below.

The LISTHORZ file contains a complete sample application demonstrating a

list box with a horizontal scroll bar. The necessary support functions are

contained in a C module that can be compiled and linked to any Windows-

based application.

Download LISTHORZ.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LISTHORZ.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LISTHORZ.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LISTHORZ.EXE

The LISTHSCR file contains the complete sources for a DLL that contains the

necessary list box support functions. These functions are exactly the same

as those in LISTHORZ. Included in this archive is an application that uses

the services of the DLL to perform the same functions as the application in

LISTHORZ.

Download LISTHSCR.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LISTHSCR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LISTHSCR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LISTHSCR.EXE

New List Box Messages:

LB_SETHORIZONTALEXTENT and LB_GETHORIZONTALEXTENT

=================================================

Two messages have been added to Windows 3.0 to support horizontal

scroll bars in list boxes:

   Message                 Description

   -------                 -----------

   LB_SETHORIZONTALEXTENT  Sets the width in pixels by which a list

                           box can be scrolled to the value of wParam

                           in the message

   LB_GETHORIZONTALEXTENT  Retrieves the width in pixels by which a

                           list box can be scrolled

By default, the horizontal scroll bar extent of a list box is 0 (zero).

Because 0 is less than the width of the list box client area, Windows will

not add a scroll bar to the window until the scroll bar extent is changed

to a value larger than the list box extent.

However, the LB_SETHORIZONTALEXTENT message does not affect the visibility

of a horizontal scroll bar. If a scroll bar is visible, sending this

message with a small extent specified will not remove it. Likewise, if a

scroll bar is not present, sending this message with a large extent will

not create one.

The next two sections of this article explain how to add and remove a

horizontal scroll bar as strings are added and deleted. The major point is

that Windows will only show or hide the scroll bar when a string is added,

inserted, or deleted.

Making the Scroll Bar Visible When Adding or Inserting a String

---------------------------------------------------------------

When a string with an extent larger than the width of the list box is to be

added, an application must send the LB_SETHORIZONTALEXTENT message before

sending an LB_ADDSTRING or LB_INSERTSTRING message.

During the process of adding or inserting a string, Windows compares the

horizontal scroll bar extent stored in the list box to the width of the

list box client area. If the client area extent is smaller than the scroll

bar extent, the scroll bar is made visible the next time the list box is

drawn.

The client area width of the list box does not include the width of the

vertical scroll bar, if it is visible. Consider a list box without a

vertical scroll bar, that is filled with strings. Each of these strings is

slightly narrower than the list box. When another string is added, and the

vertical scroll bar is caused to appear, Windows discovers that the

horizontal scroll bar extent is now greater than the width of the list box,

and adds a horizontal scroll bar.

If the scroll bar extent is less than the width of the client area of the

list box, the status of the scroll bar remains unchanged.

If the list box is not drawn after the string is added, the scroll bar will

not appear. Therefore, if the WM_SETREDRAW message is used to turn redraw

off, adding a string will not show the horizontal scroll bar until the list

box is redrawn.

Hiding the Scroll Bar When Deleting a String

--------------------------------------------

Windows only removes the horizontal scroll bar during the processing of an

LB_DELETESTRING message. Therefore, if the string to be deleted is the

longest in the list box, the horizontal scroll bar extent must be changed

to the next smaller extent value before that string is deleted. After the

string is deleted, Windows compares the stored scroll bar extent to the

width of the client area of the list box, and if the extent is smaller, the

scroll bar is removed.

If the list box is not drawn after the string is deleted, the scroll bar

will not disappear. Therefore, if the WM_SETREDRAW message is used to turn

redraw off, deleting a string will not remove the horizontal scroll bar

until the list box is redrawn.

However, if the list box is scrolled to the right by as little as one

pixel, the scroll bar will remain visible, regardless of the extent that is

set. This is done so that the user can always scroll back to the extreme

left. If the scroll bar was removed, the list box might be left in a state

where it is scrolled to the right by some amount without any way to scroll

back completely to the left.

To work around this problem, always scroll the list box to the extreme left

before deleting the longest string. If a shorter string is deleted, the

extent will remain the same and the horizontal scroll bar will not be

affected anyway. Only scroll the list box if the longest string is being

deleted.

The list box can be scrolled either completely to the left (in the case

where a long string still exists in the list box) or just enough so that

the next longest string is visible, assuming that the list box requires a

scroll bar. The sample code in the Software Library (described above)

always scrolls the list box completely left, using the WM_HSCROLL message,

as follows:

   SendMessage(hList, WM_HSCROLL, SB_TOP, 0L);

The LB_RESETCONTENT message does not affect the state of the horizontal

scroll bar even though all strings in the list box are deleted. Before an

LB_RESETCONTENT message is sent, an application must perform the following

steps:

1. Send a LB_SETHORIZONTALEXTENT message with an extent of 0 (zero).

2. Send a WM_HSCROLL message to scroll the list box completely to the

   left. This method is given above.

3. Send an LB_DELETESTRING message with an index of 0 (zero). This

   will delete the first string, if there is one, and will also remove

   the scroll bar.

If any strings are present in the list box, the first is removed by the

LB_DELETESTRING message and the scroll bar is removed, because the extent

has been set to zero. The LB_RESETCONTENT message will then remove the

remaining strings. If there are no strings in the list box, the

LB_DELETESTRING message will return an error. However, because there are no

strings in the list box, there should be no scroll bar in the first place.

Calculating Horizontal Extents of Strings

-----------------------------------------

The previous discussion mentions the extents of strings, but provides no

methods for determining these values.

Pixel extents of strings are calculated by the GetTextExtent function. This

is a GDI call that sums the pixel width of each character in a string using

the font that is currently selected into a display context represented by

an hDC.

If lpString holds a representative string and hWndListBox is the window

handle to the list box, the following steps are required to determine the

size of each string:

1. Declare the following variables:

      DWORD       dwExtent;

      HDC         hDCListBox;

      HFONT       hFontOld, hFontNew;

      TEXTMETRICS tm;

2. Use GetDC to retrieve the handle to the display context for the

   list box and store it in hDCListBox:

      hDCListBox = GetDC(hWndListBox);

3. Send the list box a WM_GETFONT message to retrieve the handle to

   the font that the list box is using, and store this handle in

   hFontNew:

      hFontNew = SendMessage(hWndListBox, WM_GETFONT, NULL, NULL);

4. Use SelectObject to select the font into the display context.

   Retain the return value from the SelectObject call in hFontOld:

      hFontOld = SelectObject(hDCListBox, hFontNew);

5. Call GetTextMetrics to get additional information about the font

   being used:

      GetTextMetrics(hDC, (LPTEXTMETRIC)&tm);

6. For each string, the value of the extent to be used is calculated

   as follows:

      dwExtent = GetTextExtent(hDCListBox, lpString, strlen(lpString))

             + tm.tmAveCharWidth;

7. After all the extents have been calculated, select the old font

   back into hDCListBox and then release it.

      SelectObject(hDCListBox, hFontOld);

      ReleaseDC(hWndListBox, hDCListBox);

There is a reason for step 5 and adding the additional width to the string

in step 6 above. If the largest value returned by GetTextExtent is used as

the parameter in the LB_SETHORIZONTALEXTENT message, the longest string

will not show completely when the list box is scrolled completely to the

right. A few pixels are clipped by the right border on the list box.

The tmAveCharWidth field in the TEXTMETRIC structure provides a consistent

number of pixels to add to the length of the string, no matter what font is

presently in use. This buffer space keeps the strings from being clipped.

As a side note, the value of tmAveCharWidth is the number of pixels by

which the list box is scrolled horizontally when the scroll bar arrows are

clicked. If a fixed pitch font is used, the list box is scrolled

horizontally by one character for each click.

Maintenance of All Extents in List Box

--------------------------------------

Many possible methods can be used to maintain a list of the extents of the

strings in the list box. One of the most convenient methods is to use

property lists, as shown in the sample code.

Every window has a property list associated with it. Each property is a

string and an associated data handle. A window stores and retrieves each

data handle using the string that labels the handle.

A sorted list of the extents for strings in the list box can be saved in a

local or global memory object. This allows each window to keep its own list

and does not require that the application maintain a mapping from the list

box to the data handle itself. The list of extents should be sorted in

descending order, so that the first extent in the list is that of the

longest string in the list box. Keeping this list sorted also allows the

application to use a binary search to find an extent in the list when one

is being inserted or deleted.

When a new string is added, insert that string's extent into the list,

maintaining the sorted order. If the new extent is placed at the top of the

list, send an LB_SETHORIZONTALEXTENT message to the list box specifying the

new extent. Do not send the message for an extent that is not the largest.

When a string is deleted, remove that string's extent from the list. If the

extent is the first in the list, then that string is the longest in the

list box. In this case, send an LB_SETHORIZONTALEXTENT to the list box

specifying the next largest extent in the list. If a smaller string is

deleted, do not send the message.

When an LB_RESETCONTENT message is used, clear the entire list of extents.

Send an LB_SETHORIZONTALEXTENT message specifying an extent of 0 (zero),

followed by an LB_DELETESTRING as outlined in the last part of the section

above titled "Hiding the Scroll Bar When Deleting a String."

Sample Code

-----------

As mentioned above, there are two archives in the Microsoft Software

Library: LISTHORZ and LISTHSCR. Each of these samples provides five support

functions that greatly facilitate the maintenance of horizontal scroll bars

in list boxes.

In LISTHORZ, these functions are found in the file LISTHELP.C. This file

can be compiled separately and linked into an application.

LISTHSCR contains the source files for a DLL that provides these five

support functions. The C file for the DLL is exactly the same as in

LISTHORZ, except that its name has changed. This archive also includes a

LISTHORZ program that uses the services of the DLL to perform the same

functions as the program in the other archive. The file LISTHAPI.H is the

include file containing prototypes of the functions exported by the DLL.

Also included is an import library, LISTHSCR.LIB, that is generated by the

makefile.

The DLL is most useful because it can support horizontal scroll bars in any

number of list boxes in any number of applications.

The remainder of this article documents the support functions:

BOOL FInitListboxExtents(HWND hList)

  Allocates local memory to store a list of string extents for the

  list box identified by hList. The handle to this local memory is

  saved in the property list of the list box. This function should be

  called after the list box is created, such as during WM_INITDIALOG

  processing.

  Parameters:

    hList    HWND   Handle to the list box that will use a horizontal

                    scroll bar.

  Return Value:

    BOOL            TRUE if there are no errors, FALSE if memory could

                    not be allocated.

----------

BOOL FFreeListboxExtents(HWND hList)

  Frees the memory allocated for the extent list of the list box

  identified by hList. The property that stores the memory handle set

  by FInitListboxExtents is removed. This function should be called

  when the list box is being destroyed.

  Parameters:

    hList    HWND   Handle to the list box that was previously used

                    with FInitListboxExtents

  Return Value:

    BOOL            TRUE if there are no errors, FALSE if memory could

                    not be freed, in which case the property is not

                    removed.

----------

void ResetListboxExtents(HWND hList)

  Removes all previously saved extents in the extent list. This is

  accomplished by calling FFreeListboxExtents and FInitListboxExtents

  in succession. The horizontal extent of the list box is set to 0

  (zero) and any horizontal scroll bar is removed. This function

  should be called before an LB_RESETCONTENT message is sent to the

  list box.

  Parameters:

    hList    HWND   Handle to the list box that will be reset.

  Return Value:

    none

----------

WORD WAddExtentEntry(HWND hList, LPSTR psz)

  Adds an extent entry into the list box's extent list. The extent

  added is that of the string pointed to by psz using the current font

  in the list box. If the extent added is larger than any other in the

  extent list, an LB_SETHORIZONTALEXTENT message is sent to the list

  box with this new extent.

  This function must be called before the string is added to the list

  box with LB_ADDSTRING or LB_INSERTSTRING.

  Parameters:

    hList    HWND   Handle to the list box to which the string is to

                    be added.

    psz      LPSTR  Pointer to string that is to be added. This

                    function must be called before the string is added

                    so that the horizontal scroll bar will be properly

                    maintained.

  Return Value:

    WORD            One of these three values:

                    0 if the string added was not the longest string

                       in the list box and the visibility of the

                       horizontal scroll bar did not change.

                    The extent of the string added, if the added

                       string was the longest and the visibility of

                       the scroll bar may have changed.

                    -1 for an error.

----------

WORD WRemoveExtentEntry(HWND hList, WORD iSel)

  Removes the extent entry of the string identified by index iSel in

  the list box. If the string to be removed is the longest in the list

  box, the list box is scrolled completely to the left and the

  horizontal extent is set to that of the next longest string.

  This function must be called before an LB_DELETESTRING message is

  sent to the list box.

  Parameters:

    hList    HWND   Handle to the list box from which a string is to

                    be removed.

    iSel     WORD   Index of the string to be removed.

  Return Value:

    WORD            One of these three values:

                    0 if the string removed was not the longest in the

                       list box and the visibility of the horizontal

                       scroll bar did not change

                    The extent of the string deleted, if the deleted

                       string was the longest and the visibility of

                       the scroll bar may have changed.

                    -1 for an error.

Additional reference words: 3.00 3.10 listbox LB_SETH LB_GETH LISTHORZ.EXE

LISTHSCR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Demo of a Keyboard Hook Function Keyboard Filter

Article ID: Q66989

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

KBHOOK is a file in the Software Library that contains sample code to

demonstrate the installation and use of a system-wide keyboard filter

function (otherwise known as a keyboard hook function). This code monitors

the status of the CAPS LOCK key. Whenever the CAPS LOCK key is pressed, its

status is displayed on the application's icon. Terminating the application

removes the keyboard filter from the system.

Download KBHOOK.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for KBHOOK.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download KBHOOK.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get KBHOOK.EXE

NOTE: The KBHOOK sample utilized the SetWindowsHook() function.

Applications written for Windows 3.1 should use the SetWindowsHookEx()

function.

MORE INFORMATION

================

KBHOOK contains an application program, KEYAPP, and a dynamic-link library

(DLL), KEYHOOK, that implements the keyboard filter function.

KEYAPP calls KEYHOOK to install the keyboard filter function and then makes

itself iconic. Windows calls KEYHOOK each time a key is pressed. When the

CAPS LOCK key is pressed, KEYHOOK posts a message to KEYAPP. KEYAPP

processes the message by painting its icon to display the current state of

CAPS LOCK. When KEYAPP is terminated, the KEYHOOK filter is removed from

the system.

Because the keyboard filter function is called regardless of the

application that is currently active, the code must be in memory at all

times. When Windows 3.0 is running in real mode with extended memory, code

for inactive applications can be placed into extended memory banks that are

switched out of memory. Windows's memory management scheme is defined so

that code in fixed DLLs will remain in memory at all times and will remain

available for execution.

For more information on the keyboard filter function, see the documentation

for the SetWindowsHook() function on pages 4-419 through 4-427 in the

"Microsoft Windows Software Development Kit Reference Volume 1" for the

Windows SDK version 3.0. For additional information on the

SetWindowsHookEx() function see pages 896-899 of "Programmer's Reference,

Volume 2: Functions" from the Windows SDK version 3.1. The "Microsoft

Windows Software Development Kit Guide to Programming" provides additional

information on DLLs.

Additional reference words: 3.00 3.10 softlib KBHOOK.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrHks


SAMPLE: Drawing a Custom Border Around a Control Window

Article ID: Q66992

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Microsoft Windows is not designed to allow a control to draw its own custom

border. If an application subclasses the control and draws a border during

the processing of the WM_PAINT message, the control will not be clipped

properly because the control does not determine the clipping when it draws

outside its client area.

The proper approach is to have the parent of the control draw the border

during the processing of a WM_PAINT message. In this case, Windows will

perform the appropriate clipping automatically.

There is a sample application in the Microsoft Software Library called

DROPSHAD that demonstrates this technique. This program shows how to create

an edit control with a "drop shadow." The parent window of the edit control

draws the drop shadow on the control's behalf.

Download DROPSHAD.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DROPSHAD.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DROPSHAD.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DROPSHAD.EXE

MORE INFORMATION

================

The following three steps draw the drop shadow:

1. During the processing of the parent window's WM_CREATE message, the

   parent creates the edit control and sets a static variable to the

   edit control's HWND (which will be needed to draw the shadow).

2. The parent windows draws the drop shadow during the processing of a

   WM_PAINT message. The parent window uses GetWindowRect() to

   determine the rectangle of the edit control in screen coordinates.

   The ScreenToClient() function converts this data to local

   coordinates, then OffsetRect() offsets the rectangle to determine

   the bounds of the shadow. (The code for this step would go very

   nicely into a DrawShadow() procedure if the application had more

   than one edit control to shadow.)

3. The parent window calls Rectangle() to draw the two rectangles that

   create the drop shadow.

The width of the drop shadow, how far the drop shadow is offset from the

corners of the edit control, and the color of the brush used to paint the

drop shadow can be varied to achieve a particular control appearance.

Additional reference words: 3.00 3.10 softlib DROPSHAD.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: MUSCROLL Custom Control Code in Software Library

Article ID: Q67247

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The Microsoft Software Library contains a custom control DLL and

documentation for a custom control class, MicroScroll. These controls are

essentially small scroll bars with no scroll box, and perform no scroll-box

tracking.

MicroScroll controls are small enough to be placed next to edit controls to

create a spin button, such as those in the Date/Time dialog box in the

Control Panel. Spin buttons are discussed on pages 86 and 87 of the IBM CUA

guide, which is included with the Windows Software Development Kit (SDK).

The archive file in the Microsoft Software Library, MUSCROLL, contains the

following files:

   Filename      Description

   --------      -----------

   MUSCROLL.DLL  MicroScroll custom control DLL. Currently, the source

                 files necessary to build the custom control are not

                 available to the public.

   MUSCROLL.H    Header file containing control styles and messages

                 that define the interface to the control.

   MUSCROLL.HLP  Windows Help file describing the control interface

                 and notes on using the control in an application.

   MUSTEST.ZIP   Code for a test program that uses MicroScroll

                 controls to implement a numeric spin button and to

                 add horizontal scrolling capabilities to a

                 single line edit control.

Download MUSCROLL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MUSCROLL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MUSCROLL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MUSCROLL.EXE

To use MicroScroll effectively with the Dialog Editor that is shipped with

the Microsoft Windows SDK version 3.0, you must first patch the Dialog

Editor executable file. For additional information on the Dialog Editor

patch, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q67200

   TITLE     : FIX: Dialog Editor Will Not Change Custom Control Style

NOTE: The Dialog Editor was fixed in the Windows SDK version 3.1.

Additional reference words: 3.00 3.10 softlib MUSCROLL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Generic Custom Control Sample Code in Software Library

Article ID: Q67250

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The Microsoft Software Library contains an archive file CUSTCONT that

contains the source code for a generic custom control. The following basic

custom control features are demonstrated:

   Registering the control class

   Creating the control

   Painting the control

   Changing the font in the control

   Gaining and losing focus

   Moving and sizing the control

The control is essentially a three-dimensional static rectangle with text.

The functions necessary to interact with the Windows Dialog Editor are

implemented in a separate module. These functions are documented in Chapter

20 of the "Microsoft Windows Software Development Kit Guide to Programming"

for version 3.0.

CUSTCONT contains two archive files. The first, CTL.ZIP, contains the

sources for the custom control DLL. The second, CTLTEST.ZIP, contains the

sources for a small program that demonstrates the use of the control.

Download CUSTCONT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for CUSTCONT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CUSTCONT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CUSTCONT.EXE

Additional reference words: 3.00 3.10 softlib CUSTCONT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Controlling the Horizontal Scroll Bar on a List Box

Article ID: Q67677

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The Microsoft Software Library contains an archive of a document that

explains how to manipulate the horizontal scroll bar on a Windows list box.

Download LBOXSBAR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LBOXSBAR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LBOXSBAR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LBOXSBAR.EXE

LBOXSBAR refers to two other Software Library files that contain sample

code: LISTHORZ and LISTHSCR. Each archive contains code to maintain a

horizontal scroll bar on a Windows list box. The code in LISTHORZ is in a C

module that can be compiled and linked to any Windows-based application.

The code in LISTHSCR is in a Windows DLL that can support multiple list

boxes in the same application.

Download LISTHORZ.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LISTHORZ.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LISTHORZ.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LISTHORZ.EXE

Download LISTHSCR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LISTHSCR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LISTHSCR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LISTHSCR.EXE

Additional reference words: 3.00 3.10 softlib LISTHORZ.EXE LISTHSCR.EXE

LBOXSBAR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCt


SAMPLE: System Bitmaps Available Through LoadBitmap() Data

Article ID: Q67709

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

All Windows version 3.0 and 3.1 display drivers are required to contain

certain bitmaps. These bitmaps are used to paint various windows, controls,

and menus. Handles to these bitmaps can be retrieved with the LoadBitmap()

function. Below is an explanation of the OBM values listed in the Windows

include file WINDOWS.H.

These values are parsed by the C Compiler only if OEMRESOURCE is defined

prior to including WINDOWS.H.

Download SYSBIT.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SYSBIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SYSBIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SYSBIT.EXE

MORE INFORMATION

================

Because Windows buttons have two states, normal and depressed (the

mouse pointer is over the icon and the mouse button is down), the

first seven shapes (bitmaps) have two forms, the normal image and the

depressed image. Both images are used to create the illusion of three

dimensions on the screen when a button is pressed. The names of

depressed images end with the letter "D"; the other images do not.

The last eleven bitmaps are no longer used by Windows, but must be

supplied for compatibility with applications that expect them to be

available.

Windows 3.1 Bitmaps

-------------------

The following four bitmaps are new for Windows 3.1:

   NOTE: The SYSBIT sample does not display these bitmaps, but they are

   illustrated in the documentation (as are the rest of the bitmaps listed

   below) for the LoadBitmap() function in the Windows SDK.

   Resource Name     Purpose

   ---------------------------------------------------------------------

   OBM_DNARROWI      A disabled down-pointing arrow for scroll bars.

   OBM_LFARROWI      A disabled left-pointing arrow for scroll bars.

   OBM_RGARROWI      A disabled right-pointing arror for scroll bars.

   OBM_UPARROWI      A disabled up-pointing arror for scroll bars.

Windows 3.00 Bitmaps

--------------------

   Resource Name       Purpose

   -------------       -------

   OBM_RESTORE         Images used as the restore button on the title

   OBM_RESTORED        bar. This is the button with both an up and

                       down arrow which is only shown when a window is

                       maximized.

   OBM_REDUCE          Images used as the minimize button on the title

   OBM_REDUCED         bar.

   OBM_ZOOM            Images used as the maximize button on the title

   OBM_ZOOMD           bar.

   OBM_RGARROW         A right-pointing arrow for scroll bars.

   OBM_RGARROWD

   OBM_LFARROW         A left-pointing arrow for scroll bars.

   OBM_LFARROWD

   OBM_UPARROW         An up-pointing arrow for scroll bars.

   OBM_UPARROWD

   OBM_DNARROW         A down-pointing arrow for scroll bars.

   OBM_DNARROWD

   OBM_CLOSE           A double-wide image that contains system menu

                       box shapes for both main windows and MDI child

                       windows.

   OBM_CHECK           A check mark used to check menu items.

   OBM_CHECKBOXES      Ten images that are used to show different

                       states of check boxes and radio buttons. The

                       images are organized in three rows of four

                       columns:

      Row 1

      -----

      Column 1:  Unchecked check box when the mouse is not pressed

                 over it.

      Column 2:  Checked check box when the mouse is not pressed over

                 it.

      Column 3:  Unchecked check box when the mouse is pressed over

                 it.

      Column 4:  Checked check box when the mouse is pressed over it.

      Row 2

      -----

      Column 1:  Unchecked radio button when the mouse is not pressed

                 over it.

      Column 2:  Checked radio button when the mouse is not pressed

                 over it.

      Column 3:  Unchecked radio button when the mouse is pressed over

                 it.

      Column 4:  Checked radio button when the mouse is pressed over

                 it.

      Row 3:

      -----

      Column 1:  Unused

      Column 2:  Grayed check box when the mouse is not pressed over

                 it.

      Column 3:  Unused

      Column 4:  Grayed check box when the mouse is pressed over it.

   OBM_COMBO           An arrow used for the push button in combo

                       boxes.

   OBM_MNARROW         An arrow used to designate cascaded menu items.

Windows 1.x/2.x Bitmaps

-----------------------

   Resource Name       Purpose

   -------------       -------

   OBM_SIZE            A size box formerly used on tiled windows.

   OBM_BTSIZE          A size box formerly used at the intersection of

                       vertical and horizontal scroll bars.

   OBM_OLD_RESTORE     Image used for the Windows 2.x restore button

                       on a windows title bar.

   OBM_OLD_REDUCE      Image used for the Windows 2.x minimize button

                       on a windows title bar.

   OBM_OLD_ZOOM        Image used for the Windows 2.x maximize button

                       on a windows title bar.

   OBM_OLD_RGARROW     A right-arrow bitmap used for Windows 2.x

                       scroll bars.

   OBM_OLD_LFARROW     A left-arrow bitmap used for Windows 2.x scroll

                       bars.

   OBM_OLD_UPARROW     An up-arrow bitmap used for Windows 2.x scroll

                       bars.

   OBM_OLD_DNARROW     A down-arrow bitmap used for Windows 2.x scroll

                       bars.

   OBM_OLD_CLOSE       The system menu bitmaps used for Windows 2.x.

   OBM_BTNCORNERS      Small circles that Windows 2.x used to draw

                       rounded corners on button controls.

Additional reference words: 3.00 3.10 softlib SYSBIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Developing a Spreadsheet Application for Windows

Article ID: Q68301

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

A spreadsheet, such as Microsoft Excel, is used to store and manipulate

data. It has a rectangular grid arranged in columns and rows. The

intersection of each column and row is a cell, the basic unit of a

spreadsheet in which the application stores data.

To develop a spreadsheet application, the predefined control types (such as

list boxes and edit controls) should not be used to represent cells. These

controls have limitations that preclude using them for large scale

purposes.

The information below describes a more efficient alternative to using

predefined controls when creating a spreadsheet type application. There is

a file in the Microsoft Software Library named SPDSHEET that contains the

sample code to demonstrate such an application.

MORE INFORMATION

================

The main technique used to develop a spreadsheet application for Windows is

to draw vertical and horizontal lines on a window to represent the cells of

a spreadsheet. Mouse hit-testing is then done to track the currently active

spreadsheet cell. To enter the spreadsheet data, only one edit control is

used. The most recent data is painted simultaneously on the current cell as

it is entered by the user. To store the spreadsheet data internally, an

array of the desired data type is created.

All the spreadsheet data and other visual information is repainted on the

main window whenever the application gets a WM_PAINT message.

The SPDSHEET sample application uses Windows API function calls to paint

the spreadsheet cells. It draws all of the solid lines using MoveTo() and

LineTo() functions. The vertical dotted lines are drawn by calling

LineDDA(), which in turn calls a callback function that draws pixels. The

application uses DrawText() to display column letters and row numbers. The

highlight on the current cell is achieved by inverting the bits on all four

sides of the cell.

Since this is a simplified version of a spreadsheet, the sample application

creates an array of 100 strings to represent spreadsheet data. The

developers of a spreadsheet application can choose to use their own data

type.

The SPDSHEET example also creates two other windows on the upper side of

its client area. One is a static window to display the position of the

current selected cell and the other is an edit control that is used to

enter spreadsheet data. As the data is entered to the edit control, it is

also drawn to the current selected cell using DrawText().

Upon receiving a WM_LBUTTONDOWN message, the application removes the

highlight from the currently selected cell and calculates the location of

the newly selected cell. The application highlights the newly selected cell

and copies the cell's contents to the edit control. The static window is

also updated to display the location of the newly selected cell.

The information corresponding to each cell's location is not stored by

SPDSHEET because the cell size is constant and the location can be

calculated. If, on the other hand, the cells were of variable sizes, some

location information would have to be stored and managed by the

application.

When the application receives a WM_PAINT message, it repaints its entire

client area, including the whole entire array of spreadsheet data. To make

this process more efficient, the application can make use of the invalid

region information sent by Windows through the PAINTSTRUCT structure.

Download SPDSHEET.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SPDSHEET.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SPDSHEET.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SPDSHEET.EXE

Additional reference words: 3.00 3.10 softlib SPDSHEET.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Sample Code Using a Dialog Box as the Main Window

Article ID: Q68556

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

A modeless dialog box can act as the main window of a Windows-based

application. Two advantages of this approach are:

 - The main window of the application can be created in the Dialog

   Editor.

 - Focus control is managed by Windows as it is for a dialog box.

The Microsoft Software Library contains a file that demonstrates the

necessary principles.

Download DLGMAIN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S12882.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLGMAIN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLGMAIN.EXE

MORE INFORMATION

================

The information below outlines the necessary modifications to the code in

GENERIC, a sample application provided with the Windows Software

Development Kit (SDK) version 3.0, that will result in a Windows-based

application that uses a modeless dialog box as its main window.

To GENERIC.C, make the following changes:

//  1. Create a global variable to hold the window handle of the

//     dialog box.

   HWND hDlgMain;

//  2. In the WinMain() procedure, declare a FARPROC variable. This

//     variable holds the procedure-instance address for the dialog

//     procedure.

   FARPROC lpfn;

//  3. Modify the CreateWindow() call in InitInstance() to specify 0

//     (zero) for nWidth and nHeight when the main window is created.

//     Do this so that the main window is not shown until the size of

//     the dialog box is known.

   hWnd = CreateWindow("GenericWClass", "Dialog as Main Window",

             WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,

             CW_USEDEFAULT, 0, 0, 0, NULL, NULL, hInstance, NULL);

//  4. In WinMain(), create a procedure-instance for the dialog

//     procedure.

   lpfn = MakeProcInstance(Dialog1, hInst);

//  5. In WinMain, create the dialog box using CreateDialog().

   hDlgMain = CreateDialog(hInst, "DIA1", hWnd, lpfn);

//  6. Add code to WinMain() to show the dialog box.

   ShowWindow(hDlgMain, SW_SHOW);

//  7. Windows sends messages to the modeless dialog box through the

//     program's main message queue. To process messages intended for

//     the dialog box, modify message queue processing in WinMain() as

//     follows:

   while (GetMessage(&msg,   // Message structure

                     NULL,   // Handle of window receiving message

                     NULL,   // Lowest message to handle

                     NULL))  // Highest message to handle

   {

      if (hDlgMain == NULL || !IsDialogMessage(hDlgMain, &msg))

      {

      TranslateMessage(&msg); // Translate virtual key codes

      DispatchMessage(&msg);  // Dispatches message to window

      }

   }

   return msg.wParam;     /* Returns the value from PostQuitMessage */

//  8. When the application receives a WM_SETFOCUS message, it must

//     set the input focus to the control that acts as the

//     application's main window. Adding the following code to

//     MainWndProc() processes the WM_SETFOCUS message as required:

   case WM_SETFOCUS:

      SetFocus(hDlgMain);

      break;

In the dialog function, make the remaining changes:

//  9. In the dialog function, declare a variable of type RECT to

//     store the bounding rectangle of the modeless dialog box.

   RECT rect;

// 10. Retrieve the dimensions of the dialog box. This information

//     will be used to calculate the size of the parent window.

   case WM_INITDIALOG:

      GetWindowRect(hDlg, &rect);

// 11. Size the parent window to be the same size as the dialog box.

   SetWindowPos(GetParent(hDlg), // Get the window handle of the

                                 // parent of the dialog box.

     NULL,                       // Identifies a window that in the

                                 // window-manager's list will

                                 // precede the positioned window.

                                 // This is not used for this example.

     0,                          // Specify the x-coordinate of the

                                 // window's upper-left corner.

     0,                          // Specify the x-coordinate of the

                                 // window's upper-left corner.

     rect.right - rect.left,     // Based on the values returned by

                                 // GetWindowRect, calculate the new

                                 // width of the main window.

     rect.bottom - rect.top + GetSystemMetrics(SM_CYCAPTION)

                            + GetSystemMetrics(SM_CYMENU),

                                 // Based on the values returned by

                                 // GetWindowRect, the height of the

                                 // caption bar, and the height of

                                 // the menu bar, calculate the new

                                 // height of the main window.

     SWP_NOMOVE | SWP_NOZORDER);

                                 // Retain current position and

                                 // ordering.

// 12. When the application receives a WM_CLOSE message, close the

//     modeless dialog box and post a WM_CLOSE message to the main

//     window.

   case WM_CLOSE:

      DestroyWindow(hDlg);  // Close the modeless dialog box using

                            // DestroyWindow.

      hDlgMain = NULL;      // Set the handle of the modeless dialog

                            // box to null.

      PostMessage(GetParent(hDlg), WM_CLOSE, NULL, NULL);

      break;

Make one change to GENERIC.RC: Modify the dialog box template to specify

the additional style WS_CHILD. Doing so will ensure that the dialog box

moves with the parent window as the parent is moved.

Additional reference words: 3.00 3.10 softlib DLGMAIN.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: DLL Installs an ISR That Can Signal an Application

Article ID: Q68560

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In the Microsoft Windows environment, an interrupt service routine

(ISR) can communicate with an application. n ISR must be in a fixed

code segment in a dynamic-link library (DLL) to ensure that the code

is always in memory and available to service the interrupt. In Windows

3.1, an ISR that supports hardware should be in an installable device

driver to enable Windows to disable the hardware when it switches

between MS-DOS tasks.

HANDLER is a set of sample programs that demonstrate how to install an

ISR, and have the ISR communicate with an application. The HANDLER DLL

installs an ISR, which in turn uses the PostMessage function to notify

the DEMO application (included with HANDLER) that an event has

occurred. The ISR is chained to the keyboard interrupt vector, and the

DEMO application maintains and displays a count of keyboard

interrupts.

This sample program illustrates how an application can detect a

hardware interrupt. This may be useful to a programmer trying to

support a hardware device in the Windows environment.

HANDLER is one of the advanced samples provided with version 3.1 of the

Microsoft Windows SDK. HANDLER can also be found in the Software Library.

Download HANDLER.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HANDLER.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HANDLER.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HANDLER.EXE

The Microsoft C Compiler and Microsoft Macro Assembler (MASM) are

required to build the files in HANDLER.

Additional reference words: 3.00 3.10 softlib HANDLER.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrIsrDll


SAMPLE: Sample Code Uses PatBlt to Drag a Frame Rectangle

Article ID: Q68569

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions  3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following information describes a procedure to smoothly drag the

window frame; this procedure is similar to the one that Windows uses

when a window is moved by dragging its caption bar. When the user

moves a window with the mouse or with the keyboard, Windows shows the

movement of the window by a moving a gray-patterned frame. The

dragging looks smooth because Windows updates only the portions of the

frame that need to be erased or drawn, leaving all other areas

untouched.

One technique to implement smooth dragging for a single rectangle is

described below. An actual frame in Windows consists of four thin

rectangles dragged together.

DRAGRECT is a file in the Microsoft Software Library that demonstrates

dragging a single rectangle and a frame.

Download DRAGRECT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DRAGRECT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DRAGRECT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DRAGRECT.EXE

MORE INFORMATION

================

To smoothly drag a rectangle, redraw only the invalid portions of the

rectangle. For example, if a rectangle is dragged up by 3 pixels, only

the top 3 pixels need to be drawn and the bottom 3 pixels erased. All

other parts of the rectangle are left alone. The same principle

applies when a rectangle is moved on a diagonal--two edges are drawn,

two edges are erased, and the bulk of the middle of the rectangle

remains the same.

To implement smooth dragging of a single solid rectangle, perform the

following eight steps:

1. When dragging begins, save the coordinates of the rectangle.

2. Draw the initial rectangle using a pattern brush and the PatBlt

   function. Windows uses its own gray brush made with a bitmap of

   alternating 0x55 and 0xAA values. In the PatBlt call, use the

   PATINVERT option to combine the pattern brush and the screen using

   the XOR operation. The XOR option is very convenient because

   another XOR operation restores the screen to its original state.

   Alternatively, use the DSTINVERT option, which performs a NOT

   operation on the destination rectangle, ignoring the current

   selected brush. A second NOT operation restores the screen to its

   original state. A NOT operation is slightly faster than an XOR

   operation; however, it is not nearly as flexible with respect to

   the nature of the rectangle drawn.

3. Each time the mouse is moved, save the new coordinates. The old

   coordinates must be retained for the time being.

4. Create an intersection rectangle of the old and new positions using

   the IntersectRect function. If this rectangle is empty, call the

   PatBlt function twice: to erase the old rectangle and to draw the

   new rectangle. This is allowed because the old and new positions

   have no overlapping region.

5. If the two rectangles intersect, update only the nonoverlapping

   regions--the edges of the old and new rectangles that are not in

   the intersection.

6. In most cases, the rectangle moves in both horizontal and vertical

   directions, which creates two regions that need updating:

      XXXXXXXXXXXX    The union of X, x, and . is the original

      XXXXXXXXXXXX       rectangle.

      x...........o   The union of O, o, and . is the new rectangle.

      x...........o

      x...........o   Erase the areas marked with an X or x.

      x...........o   Draw the areas marked with an O or o.

      x...........o

       OOOOOOOOOOOO

       OOOOOOOOOOOO

7. Each update region contains two smaller rectangles: one that makes

   up the horizontal section along the top (marked with uppercase

   characters in the diagram above) and one that makes up the vertical

   section along the side (marked with lowercase characters).

   Once the application determines the coordinates of these

   rectangles, call the PatBlt function to draw or erase them as

   appropriate. Do not draw overlapping areas twice; that is, when

   dealing with areas marked x or o, do not draw in the areas marked X

   or O, or vice versa.

   At this point, the rectangle has been moved without affecting the

   intersecting region (marked with periods) at all. Because the

   intersection was not erased or drawn, no flicker occurs and the

   dragging appears smooth.

8. When dragging stops (the mouse button is released), call the PatBlt

   function to erase the current rectangle because it is no longer

   needed.

When a window is moved by dragging the caption bar, Windows divides

the window's rectangle into four parts: the bottom, top, left, and

right lines. Each line is a rectangle because the border of a window

is usually thicker than one pixel. The dragging process above is

applied to all of these rectangles at the same time.

The DRAGRECT sample program available in the Microsoft Software Library

demonstrates the dragging process for both a single rectangle and a

frame made of four separate rectangles. Note that the sample program

is not optimized to drag a frame with the same efficiency as Windows;

it is meant only to demonstrate the concepts involved.

Additional reference words: 3.00 3.10 softlib DRAGRECT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiDrw


SAMPLE: Windows Code to Parse MS-DOS Environment Variables

Article ID: Q68647

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

PATH is a sample application for the Windows environment that

demonstrates how to parse MS-DOS environment variables. PATH will

accept any environment variable and the name of a file. A search path

is a null-terminated string that consists of a sequence of directory

specifications separated by semicolons (;). PATH searches for the

named file by searching each directory (one directory at a time) in

the order in which the directories are listed in the environment

variable.

Download PATH.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PATH.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PATH.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PATH.EXE

Additional reference words: 3.00 3.10 softlib PATH.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrIsrTsr


SAMPLE: Code Stores Resources in a Dynamic-Link Library

Article ID: Q69029

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0

----------------------------------------------------------------------

DLLDLG is a file in the Software Library that demonstrates using a dialog

template stored in a Windows dynamic-link library (DLL).

Download DLLDLG.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLLDLG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLLDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLLDLG.EXE

Additional reference words: 3.00 softlib DLLDLG2.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrRsc


SAMPLE: Using IsDialogMessage to Simulate a Dialog Box

Article ID: Q69077

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

There is a sample program in the Microsoft Software Library named ISDIALOG

that demonstrates how to create a window, add controls, and use the

IsDialogMessage function to make the window act like a dialog box. This

technique can be used in cases where superclassing a dialog box is too

costly or not possible.

By using a conventional window and not using the Dialog Manager, the

application is free to add or remove dialog functionality as

necessary.

Download ISDIALOG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download ISDIALOG.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ISDIALOG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ISDIALOG.EXE

Additional reference words: 3.00 3.10 softlib ISDIALOG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Printing Text Reports

Article ID: Q69078

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The sample program REPMKR in the Microsoft Software Library demonstrates

the code required to print a report. The report generator prints plain-text

reports in monospace fonts either on a printer or in a print-preview

window. The code to handle printer display contexts is encapsulated in the

report generator code. The interface does not require the host program to

work with printing code.

NOTE: This sample was originally written for Windows 3.0. Applications

targeted for Windows 3.1 should modify this sample's code to utilize the

Common Dialog boxes.

Download REPMKR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for REPMKR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download REPMKR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get REPMKR.EXE

MORE INFORMATION

================

The three functions of the report generator are as follows:

   Function                        Description

   --------                        -----------

   PrinterSetupDialog(void)        Brings up the standard Printer

                                   Setup dialog box

   PrinterSelectDialog(void)       Allows the user to select a printer

                                   for use by the report generator

   PrinterControl(int iCommand,    Controls page layout

      int iParam, LPSTR szParam)

The following is the table of specific commands:

   iCommand         iParam                 szParam

   --------         ------                 -------

   PC_SETCOLS       # of columns/page      Not used

   PC_SETROWS       # of rows/page         Not used

   PC_PRINT         Not used               Not used

   PC_CLEARALL      Not used               Not used

   PC_ADDLINE       -1 for next line,      LPSTR to line of text

                    (n) for line # to add

   PC_ADDBAR        -1 for width of page   LPSTR to character

                    (n) for bar width      (NULL will print '-')

   PC_SETPAGENUM    Page number            Not used

   PC_SETHEADERn    Not used               LPSTR to header,

                                           NULL will clear

   PC_ADDHEADERn    Not used               Not used

   PC_SETFOOTER1    Not used               LPSTR to header,

                                           NULL will clear

   PC_ADDFOOTER1    Not used               Not used

   PC_STARTJOB      Not used               Not used

   PC_ENDJOB        TRUE = OK,             Not used

                    FALSE = Abort

   PC_SETTITLE      Not used               LPSTR to title

                                           of print job

   PC_SETPRINTMODE  PC_CODE_PRINT or       Not used

                    PC_CODE_PREVIEW

In the REPMKR archive file is a sample program BASE that demonstrates

how to use these functions.

Each header is printed on every page, unless it is set to NULL. Each

footer is printed on every page, unless it is set to NULL. The title

of the print job is displayed in the "printing" message box.

Additional reference words: 3.00 3.10 softlib REPMKR.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


SAMPLE: Simulating Drag-and-Drop Interface for Custom Control

Article ID: Q69080

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The Microsoft Software Library contains a file named MOVECC, which

demonstrates how to simulate the Drag and Drop interface for custom

controls. By using the MoveWindow() function, this sample allows you to

click on a control and drag it to a new location.

MOVECC also demonstrates how to manipulate child window Z-order to prevent

windows from going behind other child windows, and to avoid children

painting on other children.

Download MOVECC.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MOVECC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MOVECC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MOVECC.EXE

Additional reference words: 3.00 3.10 softlib MOVECC.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: WinQuickSort(), qsort() Replacement for Windows

Article ID: Q70006

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Software Library contains object modules that implement the

Quicksort similar to the C run-time library function qsort(). These object

modules are compatible with Windows dynamic-link libraries (DLLs) and work

with FAR data pointers, including memory obtained through GlobalAlloc().

There are two versions of the object module, WINQSRTS.OBJ and WINQSRTM.OBJ,

for small-model and medium-model applications, respectively. The small-

model version uses a near pointer to the comparison function, whereas the

medium-model version uses a far pointer.

Download WINQSORT.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINQSORT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINQSORT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINQSORT.EXE

Additional reference words: 3.00 3.10 softlib WINQSORT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Code to Provide Time and Date Information

Article ID: Q70070

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The information below describes a set of functions available in the

Microsoft Software Library for formatting time and date strings using the

international settings in the Windows Control Panel.

WINTIME is a file in the Microsoft Software Library that formats time and

date strings according to the Control Panel settings.

Download WINTIME.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINTIME.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINTIME.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINTIME.EXE

MORE INFORMATION

================

Windows allows the user to specify, with the Control Panel, the appropriate

format for the date and time in the user's country. The Windows API

provides no function to format strings of date and time information

according to the Control Panel's settings. The sample code module WINTIME.C

provides C source code for five functions that an application can use to

format the date and time.

WINTIME.C is designed to be as flexible and portable as possible. The

module can be used in an application or in a dynamic-link library (DLL)

without modification.

Included with the WINTIME.C file is a sample application that demonstrates

how to use the functions.

The five functions provided by WINTIME are documented below:

1. LPSTR FAR PASCAL TimeGetCurDate(LPSTR lpszDate, WORD wFlags)

   Description:

     TimeGetCurDate() returns the current date, formatted as specified

     by the user in the Control Panel.

   Arguments:

     Type/Name

              Description

     LPSTR lpszDate

              Points to a buffer that is to receive the date. Must be

              large enough to hold the longest date possible (64 bytes

              should be large enough).

     struct tm *lpTM

              Pointer to a "tm" structure (from TIME.H) that contains

              the time and date to be formatted.

     WORD wFlags

              Specifies flags that modify the behavior of the function.

              May be any of the following:

        Flag              Meaning

        ----              -------

        0                 The date will be formatted exactly the way

                          Control Panel does it, using Windows's

                          international settings. The date will be in

                          the long date format (Sunday, January 1,

                          1991).

        DATE_SHORTDATE    Forces the date to be formatted using the

                          short date format (1/01/91).

        DATE_NODAYOFWEEK  The date will be formatted without the day

                          of week. This flag may not be used with the

                          DATE_SHORTDATE flag (that is, January 1,

                          1991).

2. LPSTR FAR PASCAL TimeGetCurTime(LPSTR lpszTime, WORD wFlags)

   Description:

     TimeGetCurTime() returns the current time, formatted as specified

     by the user in the Control Panel.

   Arguments:

     Type/Name

              Description

     LPSTR lpszTime

              Points to a buffer that is to receive the formatted

              time. Must be large enough to hold the longest date

              possible (64 bytes should be large enough).

     WORD wFlags

              Specifies flags that modify the behavior of the function.

              May be any of the following:

        Flag              Meaning

        ----              -------

        0                 The time will be formatted exactly the way

                          Control Panel does it, using Windows's

                          international settings (for example,

                          1:00:00 AM).

        TIME_12HOUR       The time will be formatted in 12 hour format

                          regardless of the WIN.INI international

                          settings. This flag may not be used with the

                          TIME_24HOUR flag (for example, 2:32:10 PM).

        TIME_24HOUR       The time will be formatted in 24 hour format

                          regardless of the WIN.INI international

                          settings. This flag may not be used with the

                          TIME_12HOUR flag (for example, 14:32:10).

        TIME_NOSECONDS    The time will be formatted without seconds

                          (for example, 2:32 PM).

3. LPSTR FAR PASCAL TimeFormatDate(LPSTR lpszDate,

                                   struct tm FAR *lpTM,

                                   WORD wFlags)

   Description:

     TimeFormatDate() returns the date, specified in the tm structure,

     formatted as specified by the user in the Control Panel.

   Arguments:

     Type/Name

              Description

     LPSTR lpszDate

              Points to a buffer that is to receive the date. Must be

              large enough to hold the longest date possible (64 bytes

              should be large enough).

     struct tm *lpTM

              Pointer to a "tm" structure (from TIME.H) that contains

              the time and date to be formatted.

     WORD wFlags

              Specifies flags that modify the behavior of the function.

              May be any of the following:

        Flag              Meaning

        ----              -------

        0                 The date will be formatted exactly the way

                          Control Panel does it, using Windows's

                          international settings. The date will be in

                          the long date format (Sunday, January 1,

                          1991).

        DATE_SHORTDATE    Forces the date to be formatted using the

                          short date format (1/01/91).

        DATE_NODAYOFWEEK  The date will be formatted without the day

                          of week. This flag may not be used with the

                          DATE_SHORTDATE flag (for example, January 1,

                          1991).

4. LPSTR FAR PASCAL TimeFormatTime(LPSTR lpszTime,

                                   struct tm FAR *lpTM,

                                   WORD wFlags)

   Description:

     Function returns the time, specified in the tm structure,

     formatted as specified by the user in the Control Panel.

   Arguments:

     Type/Name

              Description

     LPSTR lpszTime

              Points to a buffer that is to receive the formatted

              time. Must be large enough to hold the longest date

              possible (64 bytes should be large enough).

     struct tm *lpTM

              Pointer to a "tm" structure (from TIME.H) that contains

              the time and date to be formatted.

     WORD wFlags

              Specifies flags that modify the behavior of the function.

              May be any of the following:

        Flag              Meaning

        ----              -------

        0                 The time will be formatted exactly the way

                          Control Panel does it, using Windows's

                          international settings (for example,

                          1:00:00 AM).

        TIME_12HOUR       The time will be formatted in 12 hour format

                          regardless of the WIN.INI international

                          settings. This flag may not be used with the

                          TIME_24HOUR flag (for example, 2:32:10 PM).

        TIME_24HOUR       The time will be formatted in 24 hour format

                          regardless of the WIN.INI international

                          settings. This flag may not be used with the

                          TIME_12HOUR flag (for example, 14:32:10).

        TIME_NOSECONDS    The time will be formatted without seconds

                          (for example, 2:32 PM).

5. void FAR PASCAL TimeResetInternational(void)

   Description:

     This function sets some local static variables to Windows's

     current time and date format settings.

     This function should be called every time a WM_WININICHANGE

     message is sent for the [intl] section and when the DLL or

     application using these functions is invoked.

     These variables are in the DLL data segment. Therefore, if one

     application changes this information, the others will see the

     change.

Additional reference words: 3.00 3.10 softlib WINTIME.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrSys


SAMPLE: Code to Extract an Icon from a Windows .EXE File

Article ID: Q70073

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

WINRES is a file in the Microsoft Software Library that provides the

necessary structures to extract an icon from a Windows .EXE file.

NOTE: In Windows version 3.1 there is a new function named ExtractIcon() in

SHELL.DLL that performs this type of functionality. However, this article

and sample still provide a useful example of extracting .EXE file

information.

Download WINRES.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINRES.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINRES.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINRES.EXE

MORE INFORMATION

================

The following is a list of the files in the WINRES archive and how

each is used:

   Filename     Description

   --------     -----------

   WINRES.C     Application to extract .ICO and .EXE resource

                information

   WINOPEN.C    Used to display FileOpen dialog box and retrieve the

                filename

   DUMPRES.H    .EXE header information derived from the "MS-DOS

                Encyclopedia" (Microsoft Press)

Program Theory of Operation

---------------------------

To retrieve the icons from an .ICO or .EXE file, the program must retrieve

the device independent bitmaps (DIBs) that make up the icon. Although this

is a difficult process, the necessary information is documented in the "MS-

DOS Encyclopedia." A comment with each structure in the DUMPRES.H file

provides a cross-reference to the relevant information in the "MS-DOS

Encyclopedia." The .ICO file format is documented in Chapter 9, "File

Formats," in version 3.0 of the "Microsoft Windows Software Development Kit

Reference Volume 2."

Potential Enhancements to the Code

----------------------------------

1. Choosing the Display Info menu item provides a listing of resource

   information about all resources in the file. This information

   should be placed into a list box, therefore the user will be able

   to scroll through the list. Currently, the information sometimes

   scrolls off the screen.

2. Pressing the I key on the keyboard will display the TEST.ICO file.

   Currently, this filename cannot be changed.

3. This version of the program does not support Windows 2.x .EXE

   files.

Differences Between .ICO Files and .EXE Resources

-------------------------------------------------

There are only three differences between an icon in an .ICO file and

one in an .EXE file:

 - Offset to the DIB

   In an .ICO file, the offset to the DIB is the last item in the

   icoResourceCount structure, icoDIBOffset. In an .EXE file, the

   offset is found in the offset for each individual icon, the

   rc_desc.wOffset field.

 - The two reserved WORD fields before the icoDIBSize field in the .ICO

   file are filled in:

      icoPlanes   -- Filled from the BITMAPINFOHEADER.biPlanes

      icoBitCount -- Filled from the BITMAPINFOHEADER.biBitCount

   This allows an application to determine which icon is best suited

   for the display without having to read the DIB.

 - The icoDIBOffset is changed from a DWORD in the .ICO file to a WORD

   in the .EXE file. The offset value in the .ICO file is changed to

   represent an ordinal number that ranges between 1 (one) and n (the

   total number of icons in the .EXE file). Note that one ICON group

   (value RT_GROUP_ICON), which is one icon rendered at two different

   resolutions, is counted as two separate icons (value RT_ICON).

Additional reference words: 3.00 3.10 softlib WINRES.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrRsc


SAMPLE: Owner-Draw Menu Item Width Includes a Check Mark Width

Article ID: Q71061

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

When an application creates an owner-draw menu item with the MF_OWNERDRAW

style, the application receives a WM_MEASUREITEM message for that item. The

application is required to fill the MEASUREITEMSTRUCT pointed to by the

lParam of this message.

The itemWidth field of the MEASUREITEMSTRUCT is normally filled with the

actual width of the item. However, when Windows displays that menu item,

the width is increased by the width of a check mark; that is, Windows

automatically expands the item to leave space for a check mark.

To make the menu item only as wide as the actual item, fill the itemWidth

field with the width of the item, minus the width of a check mark, as

returned by GetMenuCheckMarkDimensions().

The Microsoft Software Library contains an example, MENUBMP, of owner-draw

menus with bitmaps where each item is only as large as the bitmap.

Download MENUBMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MENUBMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MENUBMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MENUBMP.EXE

MORE INFORMATION

================

The following code fragment demonstrates processing a WM_MEASUREITEM

message that results in a menu item only as wide as the actual item. In

this case, the menu is being made with bitmaps. The handle to the bitmap is

stored as part of the item data.

   // Local variables.

   LPMEASUREITEMSTRUCT     lpItem;

   HBITMAP                 hBitmap;

   BITMAP                  bm;

   WORD                    cxCheck;

   ...

   case WM_MEASUREITEM:

       // lParam is a pointer to the structure.

       lpItem = (LPMEASUREITEMSTRUCT)lParam;

       // A bitmap handle was stored in the item data.

       hBitmap = LOWORD(lpItem->itemData);

       /*

        * The width of a check mark is automatically added to

        * menu items so we need to subtract it to make the

        * menu the minimum size.

        */

       cxCheck = LOWORD(GetMenuCheckMarkDimensions());

       // Get the bitmap dimensions

       GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);

       // Set the width to the width of the bitmap - cxCheck

       lpItem->itemWidth = bm.bmWidth - cxCheck;

       // Add one to the bitmap height for some spacing.

       lpItem->itemHeight = bm.bmHeight + 1;

       break;

   ...

Additional reference words: 3.00 3.10 softlib MENUBMP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: Writing Volume Labels to Floppy and Hard Disks

Article ID: Q71498

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

To write a volume label on a floppy or a hard disk, a Windows-based

application can use the C run-time function _dos_create(). However, if

the disk already has a volume label, _dos_create() fails unless the

old label is first deleted.

SETVOL is a sample in the Microsoft Software Library that demonstrates

writing a volume label to the disk in drive A. SETVOL makes use of the

Extended File Control Block Structure and uses some in-line assembly

to check whether a volume label exists. If so, SETVOL deletes the

label.

Download SETVOL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SETVOL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SETVOL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SETVOL.EXE

Additional reference words: 3.00 3.10 softlib SETVOL.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDsk


SAMPLE: Minimal MDI Application Source in Software Library

Article ID: Q71660

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

BLANDMDI is a source code sample in the Microsoft Software Library that

demonstrates a minimal Windows multiple document interface (MDI)

application.

Download BLANDMDI.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BLANDMDI.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BLANDMDI.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BLANDMDI.EXE

MORE INFORMATION

================

The rest of this article discusses some further sources of information

regarding Windows MDI programming.

Sources of Information on MDI Programming

-----------------------------------------

Chapter 21 of the "Windows Software Development Kit Guide to

Programming" provides information on developing Windows version 3.0

MDI applications.

The Windows SDK contains a sample MDI application called MULTIPAD. BLANDMDI

was created by modifying MULTIPAD to remove all code not essential to an

MDI application.

MDIDEMO

-------

Another source of information on Windows MDI is "Programming Windows 3.1"

by Charles Petzold (Microsoft Press).

Additional reference words: 3.00 3.10 softlib BLANDMDI.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMdi


SAMPLE: BACKGRND Demonstrates Background Processing

Article ID: Q71670

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows '

   versions 3.0 and 3.1

----------------------------------------------------------------------

BACKGRND uses a PeekMessage() loop to do background processing. The

background task is to draw rectangles at random in the application's client

window. BACKGRND draws one "batch" of rectangles each time through the

PeekMessage() loop, and all the rectangles in each batch are drawn in the

same color. This provides a visual indication of how much background work

is done before BACKGRND offers to yield.

Both the "batch size" and the total number of rectangles drawn can be

changed using a menu selection.

BACKGRND does not replace the main GetMessage() loop with a PeekMessage()

loop. Instead, it enters a PeekMessage() loop only when the user chooses

the Draw! menu item.

While it draws the rectangles, BACKGRND displays a modeless dialog box

that:

1. Allows the user to cancel the background processing before all

   the rectangles have been drawn (by choosing the Cancel button)

2. Indicates both the total number of rectangles to be drawn and the

   batch size

3. Displays a "gas gauge" that indicates the percentage of the

   background task that has been completed

BACKGRND can be run along with another Windows-based application (for

example, Notepad) to illustrate the difference between "polite" and

"impolite" background processing.

If the batch size is set to a "polite" small value (for example, 10

rectangles each time through the PeekMessage loop), the user can easily

type within Notepad while BACKGRND is drawing rectangles. BACKGRND draws

rectangles in the spare time slices between the messages generated by the

user's keystrokes, and calls PeekMessage() often enough that the user will

still find Notepad responsive.

If the batch size is set to an "impolite" large value (for example, 1000

rectangles each time through the PeekMessage() loop), BACKGRND can complete

its background job much more quickly, because there are fewer calls to

PeekMessage() and thus less overhead. However, a user trying to type in

Notepad will find the keyboard so unresponsive that Notepad will be

essentially useless.

Download BACKGRND.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BACKGRND.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BACKGRND.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BACKGRND.EXE

Additional reference words: 3.00 3.10 softlib BACKGRND.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMsg


SAMPLE: Data Input Verification for Edit Controls

Article ID: Q72023

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

There is a file in the Microsoft Software Library called VERIFY.EXE that

contains sample code demonstrating the verification of the contents of

a dialog box edit control. The code reads and verifies the edit

control string as each character is entered by the user.

The contents of the edit control are verified to be legal for a specified

data type. If an illegal character is encountered, the character is removed

from the edit control and a message beep is generated. The code will verify

the input of WORD, DWORD, or FLOAT values.

Download VERIFY.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for VERIFY.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download VERIFY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get VERIFY.EXE

Additional reference words: 3.00 3.10 softlib VERIFY.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Alternate MDI Tiling Scheme Code Sample Available

Article ID: Q72135

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft Software Library contains the source code to a sample

program, MDITILE, that demonstrates how to implement an alternate tiling

scheme for the multiple document interface (MDI) of Windows version 3.0.

The alternate tiling scheme demonstrated in this sample attempts to tile

MDI child windows so they are wider than they are tall. The default MDI

tiling scheme sizes the child windows to be tall and narrow. This is

unsuitable for MDI applications based on text such as a word processor.

Download MDITILE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MDITILE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MDITILE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MDITILE.EXE

MORE INFORMATION

================

The horizontally based tiling scheme implemented in this sample uses

the following eight-step procedure:

1. Count the number of MDI child windows that are not iconic

   (represented by an icon). These are the only windows affected by

   tiling. This value is saved in "cKids."

2. Find the next square (that is, a number "n," such that some integer

   "x" is the square root, x*x == n), that is greater than the number

   of windows to tile.

3. Set a column value, "cCols," to "x-1," where "x" is the root of the

   square found in step 2.

4. Set a row counter, "cRows," to "cKids / cCols."

5. Set a remainder counter, "cMulRows," to "cKids % cCols." This

   accounts for the child windows that are not included in the base

   grid of cCols by cRows.

6. Get the dimensions of the client rectangle in which tiling is to

   occur. Note that it may be desirable to reduce the size of this

   rectangle to leave space at the bottom of the MDI client window for

   a row of icons. Divide the vertical height of the rectangle by

   cRows to get the child window height, and divide the horizontal

   width of the rectangle by cCols to get the child window width.

7. Loop through each row. In this row, the application will tile

   cCols child windows. The value "cRows-cMulRows" is the number of

   rows that can be created with cCols columns. If the rows that can

   have cCols columns have already been done, then increment cCols

   so that all remaining rows have an extra window. Since cMulRows

   are left to tile, adding one window to each row account for all

   remaining windows.

   This is also why cCols was initially "x-1." If "cCols==x," then

   the first rows (at the top of the window) would have more windows

   than rows on the bottom. If this tiling scheme is desired, set

   cCols to "x" as the assumed number of columns, then decrement

   cCols when cMulRows have been tiled.

8. Once the number of columns has been calculated, loop through the

   columns, moving each window to the appropriate section of that row.

NOTE: It is preferable to move windows with BeginDeferWindowPos(),

DeferWindowPos(), and EndDeferWindowPos(), instead of many calls to

SetWindowPos(), because the visual effect of the window movement is much

cleaner.

Additional reference words: 3.00 3.10 softlib MDITILE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMdi


SAMPLE: Appending Menu Items to Other Applications

Article ID: Q72222

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

To enhance the functionality of an existing Windows-based application, new

menu items can be added to the target application. The source application

that adds the new menu items can also respond to these menu items when they

are selected by a user. This article discusses the development of such a

source application and the pitfalls associated with using this type of

application.

There is sample code in the Software Library, in a file called SUBAPP, that

demonstrates the feature of adding menu items to another Windows-based

application.

Download SUBAPP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SUBAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SUBAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SUBAPP.EXE

MORE INFORMATION

================

To monitor the menu items of another application, the main window of that

application is subclassed using the SetWindowLong() function. In the new

window function, WM_SYSCOMMAND messages should be processed to handle the

system menu items. If the menu items belong to a pop-up menu, WM_COMMAND

should be processed. All the other messages and unrelated menu messages

should be passed to the previous window function to maintain the integrity

of the target application.

After subclassing the target application, new menu items or new pop-up

menus can be added to it. To add menu items to the system menu or an

existing pop-up menu, AppendMenu() is called, and to add new pop-up menus,

InsertMenu() is called.

To make this process work in all three modes of Windows, a fixed code

dynamic-link library (DLL) should be used. The DLL should contain the

function that adds menu items and the new window function for the target

application. This is because the code associated with such a mechanism must

be available at all times. Certain EMS (expanded memory specification)

memory configurations place all code except fixed library code segments in

application-specific EMS memory. This makes the code availability limited

to the application that owns the EMS memory. If that code is not available

to the target application, it will crash under those EMS configurations.

NOTE: For future compatibility, the subclass procedure must be in a DLL for

all modes.

Care should be taken when assigning ID (identification) values to the new

menu items. The new ID values should not conflict with the values of the

existing menu items; otherwise, the old menu items will be disabled. To

determine the existing ID values of the target application, use SPY.EXE

(included with the Windows SDK) to monitor WM_MENUSELECT messages when

selecting menu items. The wParam parameter of WM_MENUSELECT message

contains the ID value of the menu item selected.

Some applications, such as Microsoft Excel and Microsoft Word for Windows,

use more than one menu; that is, each application has an option to use a

long menu or a short one. These applications also allow their users to

customize the menus. These features could become a problem when subclassing

this type of application and monitoring new pop-up menus or new menu items.

For example, when subclassing Word for Windows, a new menu item is added

under the pop-up menu "Utility". Suppose that, when appending the new item,

the long version of the menu was selected. Later on, if the user changes to

the short version of the menu, the new added menu item will be lost because

Word for Windows would load the short version of its menus. To avoid this

problem, add menu items to the system menu of Word for Windows -- changing

the menu version does not effect the system menu.

Microsoft Excel and Microsoft Word for Windows can also display the menu

items selected in a status window at the bottom. For this purpose, these

applications use the WM_MENUSELECT message. If these applications receive a

WM_MENUSELECT for a menu item that was not originally a part of their menu,

they could crash when they refresh the status window. For this reason, in

the new window function, WM_MENUSELECT messages related to all the new menu

items should not be passed to the target application's old window function.

If there are a lot of new menu items to be added to an application,

cascading menus should be used. Such a menu structure can help minimize the

number of commands on an original pop-up menu of the target application.

As previously stated, there is a sample in the Software Library called

SUBAPP that demonstrates the feature of adding menu items to another

Windows-based application. In WinMain of SUBAPP.EXE, FindWindow() is called

to get the handle of the desired application. If the application is present

in the system, its main-window is subclassed with a new function and two

new menu items are appended to its system menu. The new function monitors

the messages of the target application. If any of those messages relate to

the newly added menu items, the messages are handled accordingly;

otherwise, they are sent to the target application's original function.

If, on the other hand, the application is not present, a message hook is

installed to monitor the execution of the desired application. The message

hook waits for the WM_PAINT message to arrive for the desired window class.

Upon receiving a WM_PAINT for the desired application, the callback hook

function subclasses the other application and appends menu items to its

system menu. The hook function then posts a message to the calling

application (SUBAPP.EXE) to unhook the message filter, since there is no

longer a need for a system message hook.

If the other application quits before the termination of SUBAPP.EXE, a

message hook is set that again waits for the activation of the desired

application to append the menu items. If SUBAPP.EXE is closed before the

target application, the added menu items are removed and the application is

no longer subclassed.

The message hook, the subclassing function for the application, and all of

the menu appending and removing calls are placed in a fixed code DLL,

called LIBSUBAP.DLL. This guarantees that SUBAPP.EXE will work properly in

all of the three modes of Windows.

SUBAPP.EXE can be used to subclass any Windows-based application as long as

the class name of the target application's main window is known. In the

application's header file (SUBAPP.H), the constant OTHER_CLASS_NAME can be

initialized to the desired application's main-window class name.

Additional reference words: 3.00 3.10 softlib SUBAPP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: TOOLHELP.DLL Functionality Demonstration

Article ID: Q72592

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The Microsoft Software Library contains a sample program that demonstrates

some of TOOLHELP.DLL's capabilities.

The TOOLHELP.EXE file contains:

   Filename     Description

   --------     -----------

   TEST.*       Sample code that demonstrates some of TOOLHELP's

                capabilities.

   TOOLHELP.*   The DLL, LIB, and so on needed to use this version of

                the TOOLHELP DLL.

Download TOOLHELP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TOOLHELP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TOOLHELP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TOOLHELP.EXE

Additional reference words: 3.00 3.10 softlib TOOLHELP.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: DDE Sample Code in Software Library

Article ID: Q73681

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

DDE is a code sample in the Microsoft Software library that demonstrates

dynamic-data exchange (DDE) and how it is programmed under Windows 3.0.

Download DDE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DDE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DDE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DDE.EXE

There are two separate applications in the DDE archive file: TICTAPE and

BARGRAPH. For each application, the archive holds a makefile, header file,

C source code, resources (.RC) file, segment definitions (.DEF) file, and

an icon.

TICTAPE is a DDE server that randomly creates and transmits data about four

stocks. BARGRAPH is a DDE client that graphically illustrates the data from

TICTAPE. TICTAPE was demonstrated at "Windows on Wall Street," June 4,

1986.

To use these applications, perform the following six steps:

1. Download from the Microsoft Software Library and expand the DDE file.

2. Build TICTAPE and BARGRAPH.

3. Start Windows.

4. Run TICTAPE.EXE.

5. Run BARGRAPH.EXE.

6. Activate TICTAPE and choose "Start Ticker Tape".

The BARGRAPH application's main window will dynamically display the

(random) values of the four stocks.

Additional information concerning DDE can be found in Chapter 22 of

the "Microsoft Windows Software Development Kit Guide to Programming"

and in Chapter 15 of the "Microsoft Windows Software Development Kit

Reference, Volume 2."

Additional reference words: 3.00 3.10 softlib DDE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Dynamically Changing Icons in a Modal Dialog Box

Article ID: Q74509

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

DLGICONS is a code sample in the Microsoft Software Library that

demonstrates how to dynamically change an icon in a modal dialog box.

Download DLGICONS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLGICONS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLGICONS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLGICONS.EXE

The modal dialog box displays an icon by creating a static child window

with the SS_ICON style. The lpWindowName parameter to the CreateWindow()

function specifies the icon to be displayed. To change the icon, the dialog

destroys the child and creates a new child in the same location.

Additional reference words: 3.00 3.10 softlib DLGICONS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Implementing Sizable Form Fields in Windows

Article ID: Q74797

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The sample program FORMEDIT in the Microsoft Software Library demonstrates

one implementation of creating a form edit under Windows. Each form can be

moved and sized with the mouse.

This program uses two novel techniques to move and size the windows. These

techniques are discussed in detail below.

Download FORMEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FORMEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FORMEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FORMEDIT.EXE

MORE INFORMATION

================

Each field on the form is a child window. Each child window has an ID value

that corresponds to a structure in a database. In this example, the

database is a simple array.

Moving Windows

--------------

The coordinates for each mouse message that is sent to the child window are

translated into the corresponding coordinates in the parent window, then

the message is passed to the parent window. In this manner, the parent

window receives all mouse messages.

If the parent window receives a WM_LBUTTONDOWN message, it checks to see if

the point of the click is within a child window; if so, a state variable is

set.

When the WM_MOUSEMOVE message is received, the parent will check the state

variable. If it set, the child window is moved to the new position selected

with the mouse.

Once the WM_LBUTTONUP message is received, the state variable is cleared.

The child window responds to the WM_MOVE message by updating its record

structure.

Sizing Windows

--------------

Each child window is created with the WS_THICKFRAME style bit.

The WM_NCPAINT message is trapped, and the DrawCoolBorder() function is

called in the place of standard nonclient painting processing. A three

dimensional effect is drawn instead of the standard Windows sizing border.

When the user moves the mouse over this area, the standard sizing arrows

are displayed, and the user can change the window size using conventional

click-and-drag methods.

The child window responds to the WM_SIZE message by updating its record

structure.

Additional reference words: 3.00 3.10 softlib FORMEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Palette Animation in Windows

Article ID: Q74799

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

"Animation" of the Windows palette is the replacement of one set of

colors in the palette by another set of colors. This article will

discuss animation and how it is used in a Windows-based application.

MORE INFORMATION

================

For an example of animation, consider a chain of rectangles on the

screen:

  +------+ +------+ +------+ +------+ +------+ +------+

  |      | |      | |      | |      | |      | |      |

  |idx 20| |idx 21| |idx 22| |idx 20| |idx 21| |idx 22| ...

  |      | |      | |      | |      | |      | |      |

  +------+ +------+ +------+ +------+ +------+ +------+

If index 20 is mapped to the color green in the palette, index 21 is

mapped to red, and index 22 is mapped to blue, a "Broadway Lights"

effect can be achieved by remapping the three colors to the different

indexes. For example, mapping red to 20, blue to 21, and green to 22,

the "lights" will appear to move to the left.

Changing the hardware registers (the system palette) is much faster

than redrawing the rectangles, since no pixels need to be updated.

Only a very small set of hardware registers need to be changed. This

allows for very fast graphical effects.

With video systems capable of supporting 256 colors, these hardware

registers are changed through palette animation, and the GDI call,

AnimatePalette() was specifically designed for this purpose.

This article is meant to be a supplement to the information provided

in the Windows Software Development Kit (SDK) manuals, not a

replacement. This article will discuss the actual steps necessary to

create and use a palette in an application from a programmer's

standpoint.

Q: What is the difference between a logical palette and the

   lpPaletteColors as referenced in the AnimatePalette() function

   description?

A: The logical palette is the one made by CreatePalette(), while the

   lpPaletteColors is a pointer to a separate memory structure that

   holds the animation colors. For this article, the term "animation

   palette" will be used to refer to the memory structure pointed to

   by lpPaletteColors.

Q: What special considerations are necessary for animation?

A: There are two necessary considerations.

   1. The palette entry in the logical palette must have the

      PC_RESERVED flag. A typical line of code that will be placed

      into the application prior to the CreatePalette() call to set

      this flag will be:

         pLogPal->palPalEntry[PaletteIndex].peFlags = PC_RESERVED;

   2. For ease of programming and animation, sequential indexes for

      the animated colors in the logical palette should be used. This

      will allow the smallest possible array to be used to contain the

      animation palette, and will produce a one-to-one correspondence

      between the logical palette and the animation palette.

Q: How is palette animation actually done?

A: There are two steps to animating the Palette:

   1. Change the color values in the animation palette to create the

      desired effect. The following example shifts the colors in the

      animation palette down one index:

        PALETTEENTRY   palentries[210];  /* The animation palette */

        ...

        palentry.peRed   = palentries[209].peRed;

        palentry.peGreen = palentries[209].peGreen;

        palentry.peBlue  = palentries[209].peBlue;

        for (i = 209; i > 0; i--)

          {

          palentries[i].peRed   = palentries[i-1].peRed;

          palentries[i].peGreen = palentries[i-1].peGreen;

          palentries[i].peBlue  = palentries[i-1].peBlue;

          }

        palentries[0].peRed   = palentry.peRed;

        palentries[0].peGreen = palentry.peGreen;

        palentries[0].peBlue  = palentry.peBlue;

   2. Call AnimatePalette(). The following example will animate the

      210 entries starting at index number 20:

        hDC = GetDC(hWnd);

        hOldPal = SelectPalette(hDC, hPal, FALSE);

        // Call Animate Palette, and realize the colors

        AnimatePalette(hPal, 20, 210, (LPPALETTEENTRY)palentries);

        RealizePalette(hDC);

        // Housekeep

        SelectPalette(hDC, hOldPal, TRUE);

        ReleaseDC(hWnd, hDC);

A sample application to draw a color wheel and "spin" it using

animation can be found in the Microsoft Software Library.

Download ANIMATE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ANIMATE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ANIMATE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ANIMATE.EXE

Additional reference words: 3.00 3.10 softlib ANIMATE.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPal


SAMPLE: Using the Palette Under Windows

Article ID: Q74908

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The palette is a mechanism to manage the colors used on the Windows

display. This article discusses the steps necessary for an application to

create and use a palette. This article is meant to supplement the

information provided in the Windows SDK documentation.

MORE INFORMATION

================

Q: What is the difference between the system palette and a logical

   palette?

A: The system palette is the palette that is actually in use (the

   colors on the screen at any given time are the colors of the system

   palette). Many applications do not create a logical palette.

   Therefore, by default, these applications use the predefined colors

   in the default system palette. The handle to this default palette

   can be obtained by calling GetStockObject(DEFAULT_PALETTE).

   A logical palette is one that the application creates; the

   application also specifies what colors the palette contains. Using

   certain GDI calls, the application can temporarily replace most of

   the system palette with the logical palette, which allows the

   application to use the colors in the logical palette. Windows

   reserves some entries in the system palette for itself. These are

   not replaced when the operations described in this article are

   used.

Q: How are logical palettes created?

A: Before creating a palette, the application should check the

   system's capabilities for color resolution. The following code

   demonstrates how this is done:

    HDC           hDCGlobal;

    NPLOGPALETTE  pLogPal;               // Pointer to program's

                                         // logical palette

    int           iNumColors;            // Number of colors supported

                                         // by device

    int           iPalSize, iRasterCaps; // Size of Physical palette

    hDCGlobal = GetDC(NULL);

    iPalSize = GetDeviceCaps(hDCGlobal, SIZEPALETTE);

    iRasterCaps = GetDeviceCaps(hDCGlobal, RASTERCAPS);

    iRasterCaps = (iRasterCaps & RC_PALETTE) ? TRUE : FALSE;

    if (iRasterCaps)

      iNumColors = GetDeviceCaps(hDCGlobal, SIZEPALETTE);

    else

      iNumColors = GetDeviceCaps(hDCGlobal, NUMCOLORS);

    ReleaseDC(NULL, hDCGlobal);

   The variable iNumColors should have a value of 2, 16, or 256,

   depending on the video card installed. This number can change in

   the future, depending on the advances in hardware technology.

   If RC_PALETTE is not set, the device is not capable of palette

   manipulation. When this is the case, however, an application can

   still create a palette, select it into a display context, and use

   the colors from the palette. GDI will create a dithered pattern

   (the disadvantages of which are discussed below) to simulate the

   color in the palette.

   After the number of colors has been determined, a block of memory

   must be allocated to hold the palette entries. A palette entry is a

   structure that contains the red, green, and blue values to specify

   the color, plus a flag. The flag is used to denote special colors

   for use in animation and other special cases. Consult the SDK

   documentation for a more complete description. For this article,

   the default flag value of NULL will be used; which means this color

   has no special attributes.

   The following code will allocate a block of memory large enough for

   the palette in local memory:

    pLogPal = (NPLOGPALETTE)LocalAlloc(LMEM_FIXED,

        (sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * (iNumColors))));

    pLogPal->palVersion = 0x300;      // Windows Version 3.0

    pLogPal->palNumEntries = iNumColors;

   Now that the memory structure has been created, it is the

   responsibility of the application to put the necessary values into

   the structure to create colors. There are two different means of

   doing this: use the default system color, or create a custom color.

   The following code examples demonstrate these two options. Assume

   that the variable PaletteIndex is valid in the range from 0 (zero)

   to (iNumColors-1).

   Use the default system color:

      pLogPal->palPalEntry[PaletteIndex].peRed = PaletteIndex;

      pLogPal->palPalEntry[PaletteIndex].peFlags = PC_EXPLICIT;

   Use a custom color:

      pLogPal->palPalEntry[PaletteIndex].peRed = <red value>;

      pLogPal->palPalEntry[PaletteIndex].peGreen = <green value>;

      pLogPal->palPalEntry[PaletteIndex].peBlue  = <blue value>;

      pLogPal->palPalEntry[PaletteIndex].peFlags = NULL;

   Once the structure has been filled with the appropriate values, it

   is time to use the GDI call CreatePalette() to make the logical

   palette:

      hPal = CreatePalette((LPLOGPALETTE)pLogPal);

   During the processing of one of the application termination message

   (WM_QUIT or WM_CLOSE), use DeleteObject(hPal) to free the system

   resources used by the palette.

Q: How are logical palettes used?

A: In Windows applications, colors are generated by three means: by

   specifying the explicit red, green, and blue color values [using

   the RGB() macro], by specifying the index into a palette [using the

   PALETTEINDEX() macro], or by specifying red, green, and blue color

   values and asking Windows to return the closest entry into the

   palette. Therefore, if a particular set of red, green, and blue

   values has been specified for palette entry 25, the following three

   lines of code will seem to be identical:

      hBrush = CreateSolidBrush(RGB(122, 15, 200));

      hBrush = CreateSolidBrush(PALETTEINDEX(25));

      hBrush = CreateSolidBrush(PALETTERGB(122, 15, 200));

   However, this is not the case. Even though the palette entry #25

   may have red, green, and blue (RGB) values of 122, 15, and 200,

   respectively, the results will be different. The first example will

   produce a brush that is a dithered pattern of the eight main system

   colors. The second and third examples will use the pure color

   defined in the palette, which produces more pleasing results.

   There are advantages and disadvantages to using RGB dithers or

   to using palette colors:

   - RGB dithers will always retain their color, even as the palette

   is changed, because they are composed of reserved colors. RGB

   dithers will appear identical on 16-color and 256-color systems.

   However, RGB dithers are less attractive than pure palette colors,

   and single-pixel-thick lines will be drawn in the pure color that

   most closely matches the dithered color.

   - Palette entries will use a true color for the red, green, and

   blue values. Single-pixel-thick lines will not be matched to one of

   the reserved pure colors. However, when the application loses

   focus, the system palette may change (due to another application

   changing the palette). This will cause the colors that the

   application uses to change. When the application regains the focus,

   it can restore the palette if it was changed. Managing the palette

   also requires additional code and memory.

   CWHEEL.EXE is a file in the Software Library that demonstrates

   managing the palette by drawing a color wheel on the screen. The

   following is an excerpt of the code in that file.

      case WM_PAINT:

          hDC = BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);

          // Bring in the palette

          hOldPal = SelectPalette(hDC, hPal, FALSE);

          // Synchronize the system palette with this application's

          // logical palette

          RealizePalette(hDC);

          // Perform any GDI operations here....

          // Bring back in the previous palette

          SelectPalette(hDC, hOldPal, TRUE);

          EndPaint(hWnd, (LPPAINTSTRUCT)&ps);

          break;

Download CWHEEL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for CWHEEL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CWHEEL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CWHEEL.EXE

Additional reference words: 3.00 3.10 softlib CWHEEL.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPal


SAMPLE: Code to Demonstrate a Button Bar

Article ID: Q74999

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The file BTNBAR.EXE in the Microsoft Software Library demonstrates one

method of adding a button bar to an application, such as the toolbar, which

is found in Microsoft Excel.

For the button bar to correctly interact with the MDI (multiple document

interface) functions of Windows, the client window must be resized to avoid

painting problems. The code in the BTNBAR file is designed to be merged

into the MULTIPAD sample application that is provided with the Windows SDK.

The remainder of this article provides some information on the design

of this button bar implementation.

Each button on the button bar is defined in an array of TOOL

structures, which is defined as follows:

  typedef struct tagTOOL

    {

    HICON     hIcon;             // 2

    WORD      CommandID;         // 2

    BOOL      bEnabled;          // 2

    WORD      x, y, dx, dy;      // 8

    }                            // --

  TOOL;                          // 14 bytes total

To conserve system resources, the determination that a given button

has been pressed is done by performing hit testing, instead of

creating separate buttons. Hit testing is demonstrated in Charles

Petzold's "Checkers" program, presented in the "Microsoft Systems

Journal."

This implementation of the button bar uses icons to label the buttons.

The DrawTool() function draws a plain button with a gray face and dark

edges, to simulate a three-dimensional object. Then, the icon

specified in the structure is drawn over the button. This icon must

use the "screen" color for its background color. This places the icon

image on the button with minimal coding effort.

When the user clicks on a button, the button bar code sends a

WM_COMMAND message to the main window (ghWnd). The wParam parameter of

this message is set to the CommandID value.

Download BTNBAR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BTNBAR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BTNBAR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BTNBAR.EXE

Additional reference words: 3.00 3.10 softlib BTNBAR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Changing the Parent of a Child Window Using SetParent

Article ID: Q75001

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

PARENT is a sample application in the Microsoft Software Library that

demonstrates how to dynamically change the parent of a child window by

using the SetParent function.

NOTE: This technique is very risky when applied to pop-up windows. Pop-up

windows do not have a parent, instead they have an owner, which is a

different relationship. Trying to change the parent of a pop-up window can

cause the application or Windows to crash.

Download PARENT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PARENT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PARENT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PARENT.EXE

Additional reference words: 3.00 3.10 softlib PARENT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Changing the Default Background Color of an MDI Client

Article ID: Q75002

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Normally, a multiple-document interface (MDI) client window defines its

background color to be the system color value COLOR_BACKGROUND+1, which is

defined in the Windows SDK file WINDOWS.H. This value corresponds to the

window background color defined by the user in the Control Panel.

It is possible to alter the default background color of an MDI client

window by subclassing the MDI client window procedure, and processing the

WM_ERASEBKGND message. All other messages are passed to the original MDI

client window procedure.

MORE INFORMATION

================

During processing of the WM_ERASEBKGND message, the class word that defines

the MDI client's background color is altered using the SetClassWord()

function. Then, control is passed to the original MDI client window

procedure to paint and update the window. When control returns from the

original MDI client window procedure, the MDI client's class word that

defines the background color is set back to its original value so that

other MDI applications currently running are not affected.

Below is a sample window procedure that can be used to subclass the

default MDI client window procedure.

LONG FAR PASCAL MdiClientWndProc(hwnd, msg, wParam, lParam)

HWND hwnd;

WORD msg, wParam;

LONG lParam;

{

  LONG lRetCode;

  switch (msg)

    {

  case WM_ERASEBKGND:

    {

    HBRUSH hbrNew, hbrOld;

                                       // create a solid purple brush

    hbrNew = CreateSolidBrush(RGB(75, 45, 145));

                                    // set the class background color

    hbrOld = SetClassWord(hwnd, GCW_HBRBACKGROUND, hbrNew);

                   // let the old window procedure handle the message

    lRetCode = CallWindowProc(lpfnMDIClientOld, hwnd, msg, wParam,

                lParam);

                             // set background back to original value

    SetClassWord(hwnd, GCW_HBRBACKGROUND, hbrOld);

    DeleteObject(hbrNew);         // all done with this, so delete it

    break;

    }

  default:

    lRetCode = CallWindowProc(lpfnMDIClientOld, hwnd, msg, wParam,

                lParam);

    break;

    }

  return lRetCode;

}

This code fragment is taken from MDISUBCL.EXE, a file in the Microsoft

Software Library, which contains an application that demonstrates this

operation.

Download MDISUBCL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MDISUBCL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MDISUBCL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MDISUBCL.EXE

Additional reference words: 3.00 3.10 softlib MDISUBCL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMdi


SAMPLE: Code Sample Manages Printing Reports in Applications

Article ID: Q75110

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

REPMGR is a file in the Software Library that contains source code

for a Windows module that manages the generating of reports from an

application. The following seven services are provided:

1. Printing textual data in a fixed-pitch font

2. Numbering each page of the report

3. Printing headers and footers and the date on each page

4. Activating the appropriate printer-setup dialog box

5. Activating a printer selection dialog box

6. Printing some very simple graphics

7. Providing a basic Print Preview operation

The following is a list of three enhancements that one might add to

provide additional functionality:

1. Provide support for proportional fonts with tabs

2. Print bitmap graphics

3. Format the text

This article discusses the services that this module provides and

contains a code fragment that demonstrates using some of the services

to print a simple report.

MORE INFORMATION

================

The interface to the report generator is as follows:

   BOOL PrinterControl(int iCommand, int iParam, LPSTR szParam);

Functions:

   iCommand         iParam                 szParam

   --------         ------                 -------

   PC_SETCOLS       # of columns           Not used

   PC_SETROWS       # of rows              Not used

   PC_PRINT         Not used               Not used

   PC_CLEARALL      Not used               Not used

   PC_ADDLINE       -1 for next line,

                    (n) for line # to add  LPSTR to line

   PC_ADDBAR        -1 for width of page,  LPSTR to character

                    (n) for bar width      (NULL = '-')

   PC_SETPAGENUM    Page number            Not used

   PC_SETHEADERn    Not used               LPSTR to header, NULL = clear

   PC_ADDHEADERn    Not used               Not used

   PC_SETFOOTER1    Not used               LPSTR to header, NULL = clear

   PC_ADDFOOTER1    Not used               Not used

   PC_STARTJOB      Not used               Not used

   PC_ENDJOB        TRUE = OK,

                    FALSE = Abort          Not used

   PC_SETTITLE      Not used               LPSTR to title

   PC_SETPRINTMODE  PC_CODE_PRINT or

                    PC_CODE_PREVIEW        Not used

   PC_GRAPHICS      Not used               LPGRAPHPARAMBLOCK

The following code prints a sample report:

void DoSampleReport (int iMode)

{

    int  i;

    char szText[80];

    PrinterControl(PC_SETPRINTMODE, iMode, 0L);

    PrinterControl(PC_SETCOLS, 80, 0L);

    PrinterControl(PC_SETROWS, 55, 0L);

    PrinterControl(PC_SETHEADER1, 0, "Header #1");

    PrinterControl(PC_SETHEADER2, 0, "Header #2");

    PrinterControl(PC_SETHEADER3, 0, "Header #3");

    PrinterControl(PC_SETTITLE, 0, "Sample Report");

    PrinterControl(PC_STARTJOB, 0, 0L);

    PrinterControl(PC_CLEARALL, 0, 0L);

    PrinterControl(PC_ADDBAR, -1, "=");

    PrinterControl(PC_ADDLINE, -1, "Added line");

    for (i = 0; i < 100; i++)

      {

      wsprintf(szText, "Loop Added Line #%d", i + 1);

      PrinterControl(PC_ADDLINE, -1, szText);

      }

    PrinterControl(PC_ADDBAR, -1, "=");

    PrinterControl(PC_PRINT, CUR_PRINT_MODE, NULL);

    PrinterControl(PC_ENDJOB, HARDCOPYONLY, NULL);

}

The following functions are provided to set up and select the printer:

   PrinterSetupDialog();

   PrinterSelectDialog();

Download REPMGR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for REPMGR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download REPMGR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get REPMGR.EXE

Additional reference words: 3.10 softlib REPMGR.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


SAMPLE: Scrolling Dialog Box Sample Code in Software Library

Article ID: Q75336

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

The procedure to define a scrolling dialog box is quite straightforward. It

is done by specifying the WS_VSCROLL and WS_HSCROLL window styles. The

dialog procedure must set the scroll range and process horizontal and

vertical scrolling messages. Windows will process the WM_PAINT message on

behalf of the dialog box.

SCROLDLG.EXE, a file in the Microsoft Software Library, contains code to a

sample application that displays a scrolling dialog box.

Download SCROLDLG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SCROLDLG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SCROLDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SCROLDLG.EXE

Additional reference words: 3.00 3.10 softlib SCROLDLG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: DLLFLOAT Converts Floating-Point Numbers to Strings

Article ID: Q75537

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

A small or medium model dynamic-link library (DLL) cannot use any of

the C run-time functions provided with Microsoft C version 6.0 to

convert a floating-point number to a character string. However, with

Microsoft C/C++ version 7.0 you can use the fcvt() and ecvt()

functions. The Windows wsprintf() function does not provide any

assistance because wsprintf() does not support floating-point numbers.

Therefore, a DLL must be compiled with Microsoft C/C++ version 7.0 or

provide its own code to perform the conversion.

DLLFLOAT is a file in the Software Library that contains a DLL-

compatible function to convert a floating-point number to a character

string.

Download DLLFLOAT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLLFLOAT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLLFLOAT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLLFLOAT.EXE

MORE INFORMATION

================

In the Windows environment, an application can use the C run-time

functions ecvt, fcvt, gcvt, and sprintf to convert a floating-point

number to a character string. However, none of these functions can be

used in a DLL because a DLL's data segment is not equal to its stack

segment and the design of each function assumes that the two segments

are identical.

To work around this assumption, a DLL must contain its own code to

perform the conversion. The DLLFLOAT example in the Microsoft Software

Library creates a function called ConvertFltToStr to convert a number

of the DOUBLE data type to a character string.

Even though ConvertFltToStr is a self-contained function, DLLFLOAT

contains a supporting function, MYfrexp, that works around a problem

in the small and medium model Microsoft C 6.0 run-time libraries.

ConvertFltToStr calls the frexp function to retrieve the mantissa and

exponent of the floating-point number. However, there is a problem

with the frexp function in the Microsoft C 6.0 small and medium model

DLL run-time libraries. For more information on this problem, please

query on the following words in the Microsoft Knowledge Base:

   frexp

The ConvertFltToStr and MYfrexp functions can be easily incorporated

into a DLL. All required variables and manifest constants are declared

inside each function. The DLL must declare a global or static string

variable to accept the results of the conversion and must include some

standard C run-time header files.

If the floating-point number is of an order of magnitude greater than

10 or less than negative 10, ConvertFltToStr converts the number using

scientific notation. Different formatting can be achieved by modifying

the code.

Additional reference words: 3.00 3.10 softlib DLLFLOAT.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: Mapping Modes Code Example

Article ID: Q75736

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

WMAPMODE is a sample program in the Microsoft Software Library that

demonstrates how to alter a window's logical coordinate system.

Download WMAPMODE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WMAPMODE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WMAPMODE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WMAPMODE.EXE

WMAPMODE implements a modeless dialog box that allows the user to

dynamically change the mapping mode attributes for the device context of

WMAPMODE's main window. These attributes are the mapping mode, window

origin, window extents, viewport origin, and viewport extents. Changing

these attributes changes the main window's logical coordinate system.

To illustrate the effects of changes to its logical coordinate system,

WMAPMODE's main window displays:

1. The current values for the mapping mode attributes.

2. The dimensions of the client area (in both device units and logical

   units).

3. The current mouse location (in both device units and logical

   units).

4. A bitmap. A second modeless dialog box allows the user to specify

   where the bitmap is drawn.

For more information on using mapping mode attributes, please refer to

the following two books:

1. The "Microsoft Windows Software Development Kit Reference, Volume

   1," Section 2.5, "Mapping Functions."

2. "Programming Windows version 3" (Charles Petzold, Microsoft Press),

   Chapter 11: "An Introduction to GDI."

Additional reference words: 3.00 3.10 softlib WMAPMODE.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiDc


SAMPLE: Creating Accelerator Tables Dynamically

Article ID: Q75738

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Sometimes it is desirable to allow the user to define accelerator keys when

running an application. No Windows function provides this functionality,

nor does the typical method of using the Resource Compiler (RC) and

embedding the accelerator table in the .EXE file. To accomplish this, the

programmer must create and manage an accelerator table.

This article outlines one method of creating accelerator tables at run

time or "on the fly." The DYNACCEL sample, which is available in the

Microsoft Software Library, demonstrates this method.

MORE INFORMATION

================

DYNACCEL demonstrates creating an accelerator table at run time rather

than in the resource file. It creates a table of accelerator keys and

their associated command identifiers. It implements a

CustomTranslateAccelerator function, which is used in place of

Windows' TranslateAccelerator function. It traps any WM_KEYDOWN

messages, checks the table to see if the key matches an accelerator

key, checks to see if the CTRL or SHIFT key is down as appropriate,

and generates a WM_COMMAND message if all conditions are met.

DYNACCEL can be enhanced to use a dynamically sized or updated table

or to include other desired functionality because everything is

created and maintained within the program.

The following code fragments are used in DYNACCEL to implement an

accelerator table at run time. The complete DYNACCEL sample can be

found in the Microsoft Software Library.

Download DYNACCEL.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DYNACCEL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DYNACCEL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DYNACCEL.EXE

/*

 * Accelerator table data structure. This has been set up arbitrarily

 * and may be altered depending on the desired functionality.

 */

typedef struct {

    BYTE cChar;

    BYTE cVirtKey;

    WORD wID;

} Accelerator;

/*

 * Array of accelerator keys. For demonstration purposes, these values

 * are predefined by DYNACCEL. An application could read in the

 * user's keystrokes and assign these values at run time or from an

 * INI file.

 */

Accelerator AccTable[TABLELENGTH] =   {

                {'A', VKCTRL, IDDA},        //CTRL+key will activate

                {'B', VKCTRL, IDDB},        //    "     "      "

                {'C', VKCTRL, IDDC},        //    "     "      "

                {'D', VKSHFT, IDDD},        //SHIFT+key will activate

                {'E', VKSHFT, IDDE},        //    "     "      "

                {'F', VKSHFT, IDDF},        //    "     "      "

                {' ', 0, IDD_UNDEFINED},    //not defined

                {' ', 0, IDD_UNDEFINED}

                                      };

/*

 * FUNCTION: CustomTranslateAccelerator(HWND, LPMSG)

 *

 * PURPOSE: Custom TranslateAccelerator for dynamic accelerator

 *          tables.

 */

int CustomTranslateAccelerator(HWND hWnd,

                               LPMSG lpMsg)

{

int i;

if (lpMsg->message == WM_KEYDOWN)

   for (i = 0; i < TABLELENGTH; i++)  //check table for a match

      {

      if ((lpMsg->wParam == AccTable[i].cChar)   //key is in table

           && (AccTable[i].wID != IDD_UNDEFINED))  //and is defined

         switch (AccTable[i].cVirtKey)

            {

            case VKCTRL:  //is CONTROL down?

               if (GetKeyState(VK_CONTROL) & 0x1000)

                  return ActivateMenuItem(hWnd, AccTable[i].wID);

               break;

            case VKSHFT:  //is SHIFT down?

               if (GetKeyState(VK_SHIFT) & 0x1000)

                  return ActivateMenuItem(hWnd, AccTable[i].wID);

               break;

            } //end switch

      } //end for loop

   return FALSE;    //key combination not found in accelerator table

}

/*

 * FUNCTION: ActivateMenuItem(HWND, WORD)

 *

 * PURPOSE: Highlight (HILITE) a top level menu item, run the command

 *          associated with a menu item, and unhighlight (UNHILITE)

 *          the top-level menu item.

 */

BOOL ActivateMenuItem(HWND hWnd,

                      WORD wID)

{

HiliteMenuItem(hWnd, GetMenu(hWnd), wID, MF_BYCOMMAND | MF_HILITE);

SendMessage(hWnd, WM_COMMAND, wID, 0L);

HiliteMenuItem(hWnd, GetMenu(hWnd), wID, MF_BYCOMMAND | MF_UNHILITE);

return TRUE;  //key combination found and processed

}

/*

 * Implementation of CustomTranslateAccelerator within WinMain

 */

    while (GetMessage(&msg, NULL, NULL, NULL))

        {

        if (CustomTranslateAccelerator(hwnd, (LPMSG)&msg) == 0)

            {

            TranslateMessage(&msg);

            DispatchMessage(&msg);

            }

        }

Additional reference words: 3.00 3.10 softlib DYNACCEL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: Using DrawPenData() or RedisplayPenData() to Display Ink

Article ID: Q75846

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

The DrawPenData() function, documented in the "Microsoft Windows for Pen

Computing: Programmer's Reference" manual, does not exactly reproduce the

appearance of the original "ink" generated by the system. However, the

RedisplayPenData function does reproduce the appearance of the ink. The

REPAINT sample application in the Microsoft Software Library demonstrates

using

RedisplayPenData.

Download REPAINT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for REPAINT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download REPAINT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get REPAINT.EXE

MORE INFORMATION

================

When the system displays ink on the screen, it uses an algorithm that is

based on a square brush. The system considers the center of the square

brush the "hot spot," around which it centers the ink. The DrawPenData()

function then uses the Windows Polyline() API to draw the line on the

screen. Polyline() assumes that its parameters specify the center points of

what is to be drawn, and that the brush is round. The difference between

the square and round brushes causes DrawPenData() to display diagonal lines

narrower than the original ink. Note that a pen that is five pixels wide

will be drawn approximately seven pixels wide by DrawPenData().

The new function, RedisplayPenData(), addresses this problem by redrawing

the ink using a square brush such that the result is identical to original

ink.

Additional reference words: 1.00 softlib REPAINT.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenInk


SAMPLE: High-Resolution Timing Services

Article ID: Q75910

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows version 3.0

----------------------------------------------------------------------

SUMMARY

=======

TIMESMP is a file in the Microsoft Software Library that demonstrates using

the high-resolution timer services provided by the Microsoft

Multimedia Windows graphical environment.

Download TIMESMP.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for TIMESMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TIMESMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TIMESMP.EXE

MORE INFORMATION

================

The timer services provided by Multimedia Windows allow an application

to schedule timed periodic interrupts or one-time interrupt events at

a higher resolution than is available through the standard Windows

timer services.

Unlike the Windows timer services, the Multimedia timer services are

interrupt-based. Rather than posting WM_TIMER messages to a message

queue, the Multimedia service calls a specified function at interrupt

time. Because the callback code is accessed at interrupt time, it must

adhere to strict programming guidelines. In particular, only a very

limited set of system function calls may be made, and the callback

function must reside in a fixed-code dynamic-link library (DLL).

The Multimedia timer services are useful for applications that demand

high-resolution timing, such as a MIDI sequencer. For less demanding

synchronization tasks, use the SetTimer function provided by Windows.

The sample application TIMESMP demonstrates using the timer services

and a callback function residing in a fixed code DLL.

Additional reference words: 3.00 softlib TIMESMP.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMTimer


SAMPLE: ENTER & TAB Keys in Dialog Box Multiline Edit Control

Article ID: Q76474

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

In an application running under Windows version 3.0 or 3.1, when the user

interacts with a dialog box and presses the ENTER key, the application

accepts any changes made to information in any control of the dialog box

and dismisses the dialog box. However, when the dialog box contains a

multiline edit control (MLE), it may be considered more intuitive for the

user to use the ENTER key to advance to the next line in the edit control.

Windows 3.0 and 3.1 use the CTRL+ENTER key combination for this purpose.

Similarly, Windows uses the TAB key to move the input focus to the next

control in the tabbing sequence in a dialog box. However, in an edit

control, it might be useful for the user to be able to enter TAB

characters. Windows uses the CTRL+TAB key combination for this purpose.

Windows version 3.1 defines the ES_WANTRETURN edit control style, which

changes the behavior of the ENTER key in an MLE in a dialog box. If an

application is designed to run only under Windows versions 3.1 and later,

specify the ES_WANTRETURN edit control style. None of the three techniques

described below is necessary.

This article discusses three different methods that can be used to modify

the behavior of the ENTER key in an MLE in an application's dialog box.

These methods are compatible with Windows versions 3.0 and 3.1. Methods 1

and 3 below can be adapted to modify the behavior of the TAB key, if

desired.

A major disadvantage of any of these methods is that the ENTER or TAB key

will no longer act as it does in other applications, and its behavior no

longer will be what an experienced Windows user would expect.

MLEENTER is a file in the Microsoft Software Library that demonstrates two

of the methods described in this document.

Download MLEENTER.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MLEENTER.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MLEENTER.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MLEENTER.EXE

MORE INFORMATION

================

Under versions of Windows earlier than 3.0, an edit control subclass

procedure could respond to the WM_GETDLGCODE message with DLGC_WANTALLKEYS

to receive all keyboard input. This technique is not effective in Windows

3.0 or later.

METHOD 1

--------

This method involves subclassing the MLE. It is most useful when the edit

control is already subclassed for another reason because the amount of

additional code is minimal. This method involves three steps:

1. Check for a WM_KEYDOWN message with wParam set to VK_RETURN.

2. Post a WM_CHAR message with wParam set to 0x0a to the edit control.

3. Do not pass the WM_KEYDOWN message to the original window procedure

   by returning immediately from the subclass procedure.

The following code fragment demonstrates this method:

    // In the subclass procedure

    switch (msg)

        {

        case WM_KEYDOWN:

            if (VK_RETURN == wParam)

                {

                PostMessage(hWnd, WM_CHAR, 0x0A, 0L);

                return 0L;

                }

            break;

        ...

        }

    return CallWindowProc(...);

The disadvantage to subclassing is that it may be more fragile, with

respect to changes in future versions of Windows, than other methods.

METHOD 2

--------

This method uses the DM_GETDEFID message that Windows sends to a dialog box

procedure when the user presses the ENTER key in a dialog box. This method

has the additional advantage of easily handling multiple multiline edit

controls in the same dialog box and involves three steps:

1. Process WM_COMMAND messages with the HIWORD(lParam) set to

   EN_SETFOCUS and EN_KILLFOCUS to determine if an MLE has the focus.

   When EN_SETFOCUS signals that a MLE has the focus, set a static

   flag to TRUE. When EN_KILLFOCUS signals that a MLE has lost the

   focus, reset the flag to FALSE.

2. When the dialog procedure receives a DM_GETDEFID message, an edit

   control has the focus, and the ENTER key is down, post a WM_CHAR

   message with wParam set to 0x0a to the edit control with the focus.

3. If an edit control had the focus, return TRUE from the dialog

   function; otherwise, the function must return FALSE. Failing to

   return FALSE will prevent the ENTER key from behaving properly when

   an edit control does not have the focus.

The following code fragment demonstrates this procedure:

    static fEditFocus;

    switch (msg)

        {

        case WM_COMMAND:

            // ID_EDIT is a multiline edit control

            if (ID_EDIT == wParam)

                {

                if (EN_KILLFOCUS == HIWORD(lParam))

                    fEditFocus = FALSE;

                if (EN_SETFOCUS == HIWORD(lParam))

                    fEditFocus = TRUE;

                }

            else

                ...

            break;

        case DM_GETDEFID:

            /*

             * Check if an edit control has the focus and that

             * the ENTER key is down. DM_GETDEFID may be sent

             * in other situations when the user did not press

             * the ENTER key.

             */

            if (fEditFocus && (0x8000 & GetKeyState(VK_RETURN)))

                {

                PostMessage(hEdit, WM_CHAR, 0x0A, 0L);

                return TRUE;

                }

            break;

        }

    return FALSE;

METHOD 3

--------

Applications that use modeless dialog boxes are required to filter messages

through the IsDialogMessage() function. The IsDialogMessage() function

modifies certain messages to implement dialog box behavior. For example,

the ENTER key message is modified to generate a WM_COMMAND message with

wParam set to IDOK.

An application is, however, free to modify the message before passing it to

the IsDialogMessage() function. The code example below modifies the

WM_KEYDOWN message containing a VK_RETURN to be a EM_REPLACESEL message

with a carriage return (CR) and linefeed (LF) combination.

The disadvantage to this method is that it places additional code in the

main message loop for the application, slowing the processing of every

message. In addition, code in the message loop is far removed from the

dialog procedure, and is therefore harder to maintain.

The following code fragment demonstrates this method:

    /*

     * hWndEditControl is the handle to the multiline edit control.

     * hWndModeless is the handle to the modeless dialog box.

     */

    while (GetMessage(&msg, NULL, 0, 0))

        {

        if (hWndEditControl == msg.hWnd

                && WM_KEYDOWN == msg.message

                && VK_RETURN == msg.wParam)

            /*

             * Normally, Windows will translate this to IDOK.

             * Perform a custom translation to something more useful

             * (replace selection with a carriage return-linefeed).

             */

            {

            msg.message = EM_REPLACESEL;

            msg.wParam  = 0;

            msg.lParam  = (long)(LPSTR)"\015\012";

            }

        if (!IsDialogMessage(hWndModeless, &msg))

            {

            TranslateMessage(&msg);

            DispatchMessage(&msg);

            }

        }

If the functionality of a modal dialog box is desired in an application, it

can be simulated by using a modeless dialog box that disables its parent

window when the dialog is created.

Additional reference words: 3.00 3.10 softlib MLEENTER.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Creating a Custom Raster Font

Article ID: Q76535

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Fonts are stored as resources in resource-only dynamic-link libraries

(DLLs). The process of creating a custom font library involves

creating new font resources and inserting them into a DLL that has no

code. Fonts must be in a resource-only library.

The Windows 3.x Font Editor supports editing raster fonts compatible

with Windows versions 2.x and Windows version 3.x.

It is also possible to create a font-resource DLL that does have a

code segment, which alleviates the problem of having to use a special

linker.

Sample code that demonstrates using the normal linker is also available in

the Software Library, in a file called MYFONT.

Download MYFONT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MYFONT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MYFONT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MYFONT.EXE

MORE INFORMATION

================

Basic Steps (Overview)

----------------------

  I. Create font files using the Font Editor.

 II. Create a font-resource script.

III. Create a dummy code module.

 IV. Create a module-definition file that describes the fonts.

  V. Compile and link the sources.

NOTE: Read Chapter 18 of the "Microsoft Windows Software Development

Kit Guide to Programming." The following procedure is very similar.

Step I: Create a Font File

--------------------------

1. Invoke the Font Editor.

2. Open an existing font file (FNT).

3. Edit the cell arrays and attributes of the existing font.

4. Save the new font under a different name.

Note 1: It is not possible to generate a new font from scratch; an

existing font file must be edited. Two fonts, ATRM1111.FNT and

VGASYS.FNT, are supplied with the Windows 3.x SDK to provide a font on

which to base new fonts.

Note 2: The names of the font formats are deceiving. Windows

3.0-compatible format works only in 386 enhanced mode. Window

2.0-compatible format works in all modes; therefore, it is usually

better to save fonts in 2.0 format.

Step II: Create a Font Resource Script

--------------------------------------

1. Create a resource script (RC) file.

2. Add one FONT statement per font file created. For example:

      MyFont1 FONT  MYFONT1.FNT

      MyFont2 FONT  MYFONT2.FNT

Step III: Create a Dummy Code Module

------------------------------------

1. Write an assembly language procedure that generates no code.

2. Assemble the code to create an object file (OBJ). (This step may

   seem unnecessary but it is required; otherwise, the linker will

   complain because the linker will create an executable that does not

   have any object files. Creating the dummy code module with its null

   code segment forces the linker to create the required executable DLL).

The code for the dummy code segment might resemble the following:

          .xlist

          include cmacros.inc

          .list

          sBegin CODE

          sEnd   CODE

          end

Step IV: Create a Module Definition File

----------------------------------------

1. Add a LIBRARY statement with the font resource title.

2. Add a DESCRIPTION statement that indicates the font characteristics.

3. Add a STUB statement in case the library is invoked from MS-DOS.

4. Add a DATA statement with the NONE attribute.

The DEF file for a font library might resemble the following:

   LIBRARY FONTLIB

   DESCRIPTION 'FONTRES 133, 96, 72: MyFont, Terminal (7 point)'

   STUB 'WINSTUB.EXE'

   DATA NONE

Note: The DESCRIPTION statement specifies a string that describes the

font attributes, and supplies a comment that is displayed by the

Windows Control Panel when the font is loaded.

WINSTUB.EXE is a small file that prints the message "This application

requires Microsoft Windows" if the user tries to run the application

under MS-DOS.

The NONE attribute indicates that the library does not require its own

automatic data segment.

The description string MUST begin with the FONTRES text so that

Windows will know that this is a font resource library.

(See the "Microsoft Windows Software Development Kit Guide to

Programming" for more information and examples.)

Step V: Building the Font Resource Library

------------------------------------------

1. Use MASM to assemble the dummy code into an object file.

2. Use LINK4 to generate the library body.

3. Use RC to insert the font into the library.

4. Rename the font library to have the FON extension.

The following is an sample makefile:

     all: fontlib.exe

     fontlib.obj: fontlib.asm

         masm fontlib.asm;

     fontlib.exe: fontlib.mak fontlib.def fontlib.obj \

                  fontlib.rc fontlib.fnt

         link4 fontlib.obj, fontlib.exe, NUL, /NOD, fontlib.def

         rc fontlib.rc

         rename fontlib.exe fontlib.fon

Using LINK Instead of LINK4:

----------------------------

Important note: The specification of LINK4 in the sample above is not

an error. The standard linkers supplied with Microsoft C version 5.1

and Microsoft C version 6.0 produce error messages when an attempt is

made to create an executable file that has no segments. LINK4.EXE is

not shipped with the Windows 3.x SDK. However, it is shipped with the

Windows 2.x SDK and with the Windows 3.x DDK.

If Steps III, IV, and V of the procedure given above are modified as

follows, LINK versions 5.12 and later can be used to create font

files:

NEW Step III: Create a Dummy Code Module

----------------------------------------

Create a code segment in the dummy code module by creating an empty

Windows Exit Procedure (WEP). This code might resemble the following:

          .xlist

          include cmacros.inc

          .list

          sBegin CODE

          cProc WEP,<FAR,PASCAL,PUBLIC>,<si,di>

               parmW EntryCode

          cBegin WEP

          cEnd WEP

          cEnd CODE

          end

NEW Step IV: Create a Module Definition File

--------------------------------------------

Modify the DEF file provided above to add the following lines:

   EXETYPE   WINDOWS

   CODE      MOVEABLE DISCARDABLE

   EXPORTS   WEP @1 RESIDENTNAME

NEW Step V: Building the Font Resource Library

----------------------------------------------

Modify the makefile to refer to LINK instead of to LINK4.

Using MASM 6.0 Instead of MASM 5.1

----------------------------------

If the font file is built using version 6.0 of the Microsoft Macro

Assembler (MASM), use version 5.3 of the CMACROS.INC file included

with MASM instead of version 5.2 of the file included with the Windows

SDK.

To access the fonts, use AddFontResource() with the DLL name, and

RemoveFontResource(). Use CreateFont() or CreateFontIndirect() to

retrieve a handle to a font with the specified attributes. Use

SelectObject() to put the font into a specified DC.

The face name of the font (for example, "System" or "Helv") can be

specified when the font is created using the Font Editor. This same

face name is specified as the lpFaceName parameter when calling

CreateFont() or CreateFontIndirect(). The face name can be any name

desired.

Additional reference words: 3.00 3.10 softlib MYFONT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiFnt


SAMPLE: Demonstration of WH_CALLWNDPROC & WH_GETMESSAGE Hooks

Article ID: Q76588

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

HOOKALL is a sample program in the Software Library that demonstrates the

use of WH_GETMESSAGE and WH_CALLWNDPROC hooks. The sample contains the code

for a dynamic-link library (DLL) with functions to set and remove the

hooks, as well as the hook filter functions. The filter functions use

OutputDebugString to display a message when they receive a WM_LBUTTONDOWN

message. The sample also contains code for an application that tests the

DLL.

Download HOOKALL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HOOKALL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HOOKALL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HOOKALL.EXE

Additional reference words: 3.00 3.10 softlib HOOKALL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrHks


SAMPLE: Code Replaces sscanf in DLLs for Windows

Article ID: Q76684

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Microsoft C run-time library function sscanf is not compatible for use

with a dynamic-link library (DLL) for the Microsoft Windows graphical

environment compiled for the small or medium memory model. The sscanf()

function relys on near pointers in these memory models and fails when the

stack segment (SS) and data segment (DS) are not the same.

WSSCANF is a file in the Software Library that can serve as a

limited replacement for this function.

Download WSSCANF.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WSSCANF.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WSSCANF.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WSSCANF.EXE

MORE INFORMATION

================

The sscanf(), fprintf(), and scanf() functions are not available in small

or medium model DLLs for the Windows environment.

There are two factors that cause these functions to be incompatible:

1. These functions rely on near pointers.

2. These functions expect SS == DS.

Because neither of these conditions is true when a function in a DLL

uses data from an application, these functions are not available.

The WSSCANF file in the Software Library contains the source code to a

wsscanf() function that can serve as a limited replacement for the sscanf

function. The wsscanf() code is based on the sscanf() source code in the

Microsoft C run-time library. The source code has been modified to work

correctly in a DLL, and requires that all parameters are specified as FAR

pointers. The following code demonstrates using the wsscanf() function:

   char   szBuf[] = "1 3 b000:0200";

   int    nValue1, nValue2;

   LPSTR  lpPtr;

   wsscanf(szBuf, "%d %d %p", (int FAR *)&nValue1,

            (int FAR *)&nValue2, (LPSTR FAR *)&lpPtr);

Note that the first two parameters are not explicitly typecast in the

function call. The function prototype typecasts the first two

parameters automatically; however, the application must typecast each

subsequent parameter. If the application does not typecast each

parameter, when the application calls wsscanf an unrecoverable

application error (UAE) occurs.

The wsscanf() function does not support floating point numbers (the %f,

%g, and %e format specifiers).

Additional reference words: 3.00 3.10 softlib WSSCANF.EXE

KBCategory: kbprg kbfile

KBSubcategory: TlsMisc


SAMPLE: Writing a Windows Application Using MASM 6.0

Article ID: Q77256

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Using the high-level language features of the Microsoft Macro

Assembler (MASM) version 6.0, it is now much simpler to write a

complete Windows program in MASM than with previous versions of the

program.

A program called MASMWIN in the Microsoft Software Library demonstrates

what is required to write a complete Windows program using MASM 6.0.

Download MASMWIN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MASMWIN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MASMWIN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MASMWIN.EXE

MASMWIN demonstrates a number of features of MASM 6.0. It demonstrates

the use of alternate PROLOGUE and EPILOGUE code generation. It also

demonstrates function prototyping and the use of the INVOKE feature.

While MASM provides a complete programming environment with high-level

language features, applications written in MASM will be much more

difficult to transfer to future versions of Windows that run on non-

Intel platforms.

MORE INFORMATION

================

Using the OPTION:PROLOGUE and OPTION:EPILOGUE directives in MASM 6.0,

an application can cause MASM 6.0 to generate any type of prologue or

epilogue code desired. For this program, it creates the appropriate

Windows code. The macros to perform this task are contained in the

file WINPRO.INC. The two declarations, ?WINDOWS=1 and ?PMODE=1, affect

the generation of the prologue and epilogue code.

The ?WINDOWS=1 declaration will cause Windows prologue and epilogue

code to be generated for all FAR functions. All other functions are

declared with the normal function stack frame.

The ?PMODE=1 declaration causes the Windows prologue and epilogue code

to be generated only for FAR functions declared as EXPORT. This code

takes advantage of the fact that in protected mode, Windows does not

walk the stack.

The program includes a WINDOWS.INC file that is different from the one

included in Windows Software Development Kit (SDK) version 3.0. This

WINDOWS.INC file was created by running WINDOWS.H through the H2INC

utility provided with MASM 6.0. This provides prototypes for all of

the Windows functions and also translates C structures to

corresponding MASM structures. This file allows the INVOKE feature of

MASM 6.0 to be used to call Windows functions. The INVOKE function

handles all the parameter passing and stack clean up. To use this

file, it is necessary to include the following line in the source code

before the line that includes the new WINDOWS.INC:

   OPTION CASEMAP:NONE

This causes the assembler to maintain case sensitivity when dealing

with symbols.

Additional reference words: 3.00 3.10 softlib MASMWIN.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsMisc


SAMPLE: Changing Color Bitmaps to Monochrome

Article ID: Q77282

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

It is often desirable to convert a color bitmap into a monochrome

bitmap so that it can be used to dynamically create a cursor (or

icon). The procedure is relatively simple and is described in this

article.

BIT2MONO is a sample application in the Microsoft Software Library that

demonstrates converting a color bitmap to a monochrome bitmap. It also

demonstrates the effect of changing the background and text color on a

monochrome bitmap.

Download BIT2MONO.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BIT2MONO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BIT2MONO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BIT2MONO.EXE

MORE INFORMATION

================

Converting a color bitmap to a monochrome bitmap basically involves

three steps:

1. Select the color bitmap into a compatible memory DC (display

   context).

2. Use GetDIBits to retrieve the bitmap information and create a color

   DIB (device independent bitmap).

3. Use SetDIBits to move the color DIB into a monochrome bitmap,

   performing the "smart" conversion from color to monochrome.

The resulting monochrome bitmap has the same bitmap "pattern," in a

monochrome format.

The following code sample demonstrates this process:

     hbmLoaded = LoadBitmap(hInst, "mybitmap");

     // convert color bitmap to monochrome

     hbmMono = ColorDDBToMonoDDB(hbmLoaded, 0, 0, NULL);

     DeleteDC(hDCMem);

     ReleaseDC(hWnd, hDC);

The DibNumColors, PaletteSize, and ColorDDBToMonoDDB functions are

listed below. They are based on code found in the SHOWDIB example

provided with the Windows Software Development Kit (SDK).

#define WIDTHBYTES(bits)  (((bits) + 31) / 32 * 4)

WORD DibNumColors (pv)

VOID FAR * pv;

{

    int                bits;

    LPBITMAPINFOHEADER lpbi;

    LPBITMAPCOREHEADER lpbc;

    lpbi = ((LPBITMAPINFOHEADER)pv);

    lpbc = ((LPBITMAPCOREHEADER)pv);

    // With the BITMAPINFO format headers, the size of the palette is

    // in biClrUsed. In the BITMAPCORE-style headers, it depends on

    // the bits per pixel (2 raised to the power of bits/pixel).

    if (lpbi->biSize != sizeof(BITMAPCOREHEADER))

    {

        if (lpbi->biClrUsed != 0)

            return (WORD)lpbi->biClrUsed;

        bits = lpbi->biBitCount;

    }

    else

        bits = lpbc->bcBitCount;

    switch (bits)

       {

        case 1:

            return 2;

        case 4:

            return 16;

        case 8:

            return 256;

        default:

            // A 24 bit DIB has no color table

            return 0;

        }

}

WORD PaletteSize(pv)

VOID FAR * pv;

{

    LPBITMAPINFOHEADER lpbi;

    WORD               NumColors;

    lpbi      = (LPBITMAPINFOHEADER)pv;

    NumColors = DibNumColors(lpbi);

    if (lpbi->biSize == sizeof(BITMAPCOREHEADER))

        return NumColors * sizeof(RGBTRIPLE);

    else

        return NumColors * sizeof(RGBQUAD);

}

HBITMAP ColorDDBToMonoDDB(hbm, biStyle, biBits, hpal)

HBITMAP      hbm;

DWORD        biStyle;

WORD         biBits;

HPALETTE     hpal;

{

    BITMAP               bm;

    BITMAPINFOHEADER     bi;

    BITMAPINFOHEADER FAR *lpbi;

    DWORD                dwLen;

    HANDLE               hdib;

    HANDLE               h;

    HDC                  hdc;

    HBITMAP              hbmMono;

    if (!hbm)

        return NULL;

    if (hpal == NULL)

        hpal = GetStockObject(DEFAULT_PALETTE);

    GetObject(hbm, sizeof(bm), (LPSTR)&bm);

    if (biBits == 0)

        biBits = bm.bmPlanes * bm.bmBitsPixel;

    bi.biSize          = sizeof(BITMAPINFOHEADER);

    bi.biWidth         = bm.bmWidth;

    bi.biHeight        = bm.bmHeight;

    bi.biPlanes        = 1;

    bi.biBitCount      = biBits;

    bi.biCompression   = biStyle;

    bi.biSizeImage     = 0;

    bi.biXPelsPerMeter = 0;

    bi.biYPelsPerMeter = 0;

    bi.biClrUsed       = 0;

    bi.biClrImportant  = 0;

    dwLen = bi.biSize + PaletteSize(&bi);

    hdc = GetDC(NULL);

    hpal = SelectPalette(hdc, hpal, FALSE);

    RealizePalette(hdc);

    hdib = GlobalAlloc(GHND, dwLen);

    if (!hdib)

        {

        SelectPalette(hdc, hpal, FALSE);

        ReleaseDC(NULL, hdc);

        return NULL;

        }

    lpbi = (VOID FAR *)GlobalLock(hdib);

    *lpbi = bi;

    // Call GetDIBits with a NULL lpBits parameter; it will calculate

    // the biSizeImage field.

    GetDIBits(hdc, hbm, 0, (WORD)bi.biHeight,

        NULL, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);

    bi = *lpbi;

    GlobalUnlock(hdib);

    // If the driver did not fill in the biSizeImage field,

    // calculate it.

    if (bi.biSizeImage == 0)

        {

        bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits)

            * bm.bmHeight;

        if (biStyle != BI_RGB)

            bi.biSizeImage = (bi.biSizeImage * 3) / 2;

        }

    // Reallocate the buffer big enough to hold all the bits.

    dwLen = bi.biSize + PaletteSize(&bi) + bi.biSizeImage;

    if ((h = GlobalReAlloc(hdib, dwLen, 0)))

        hdib = h;

    else

        {

        GlobalFree(hdib);

        hdib = NULL;

        SelectPalette(hdc, hpal, FALSE);

        ReleaseDC(NULL, hdc);

        return hdib;

        }

    // Call GetDIBits with a NON-NULL lpBits parameter, to actually

    // get the bits this time.

    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (GetDIBits(hdc, hbm, 0, (WORD)bi.biHeight,

             (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi),

             (LPBITMAPINFO)lpbi, DIB_RGB_COLORS) == 0)

         {

         GlobalUnlock(hdib);

         hdib = NULL;

         SelectPalette(hdc, hpal, FALSE);

         ReleaseDC(NULL, hdc);

         return NULL;

         }

    // Finally, create a monochrome DDB, and put the DIB into it.

    // SetDIBits does smart color conversion.

    hbmMono = CreateBitmap((WORD)lpbi->biWidth, (WORD)lpbi->biHeight,

                           1, 1, NULL);

    SetDIBits(hdc, hbmMono, 0, lpbi->biHeight,

              (LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi),

              (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);

    bi = *lpbi;

    GlobalUnlock(hdib);

    GlobalFree(hdib);

    SelectPalette(hdc, hpal, FALSE);

    ReleaseDC(NULL, hdc);

    return hbmMono;

}

An application can create a cursor from the monochrome bitmap produced

by ColorDDBToMonoDDB. The application can use the bitmap as either the

ANDbitPlane or the XORbitPlane parameter to CreateCursor. The

following code demonstrates this procedure:

    // Get only the bitmap's bits, and load into a BYTE array of

    // correct size.

    // In this example, the bitmap created happens to have the

    // dimensions needed for a cursor or icon. This may not always be

    // the case. It may be necessary to "stretch" or "compress" the

    // bitmap to the correct size, using StretchDIBits or StretchBlt

    // (depending at what point the change in size is done).

    xsize = GetSystemMetrics(SM_CXCURSOR);

    ysize = GetSystemMetrics(SM_CYCURSOR);

    GetObject(hbmMono, sizeof(BITMAP), (LPSTR)&bm);

    GetBitmapBits(hbmMono, (bm.bmWidthBytes * bm.bmHeight),

                     (LPSTR)XORbitPlane);

    // The call above uses bm.bmWidthBytes instead of planes and

    // bitsPixel because the former takes into account the fact that

    // some drivers might pad scan lines for speed reasons.

    hBitCursor = CreateCursor(ghInstance, 0, 0, xsize, ysize,

                                           ANDbitPlane, XORbitPlane);

The above procedure also applies to the CreateIcon function.

The following two notes should be considered when an application uses

this procedure:

 - It is always wise to call GetSystemMetrics to determine the

   appropriate size of cursors or icons for the installed display.

   This removes the assumption that the size is always 32 x 32, and

   allows the application to create the cursor or icon appropriately.

 - Monochrome merely means one drawing color (in addition to the

   background color). The system uses the current background and text

   colors chosen for the application (or defaults to the system-wide

   choices). An application can use SetBkColor, SetBkMode, and

   SetTextColor to modify the choice of colors in each display context

   (DC) if desired.

Additional reference words: 3.00 3.10 softlib BIT2MONO.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Raising Text Size Limit for Edit Controls

Article ID: Q77287

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

By default, the buffer for an edit controls is allocated from the

application's data segment. Because the data segment is also used to store

information for other controls, space in the data segment is a scarce

resource.

GLBEDIT is a code sample in the Microsoft Software Library that

demonstrates how an edit control can have its own data segment.

Download GLBEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GLBEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GLBEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get GLBEDIT.EXE

Normally, edit controls in a dialog box use one common global data segment

per dialog box. If the dialog box has style DS_LOCALEDIT, edit controls use

the data segment pointed to by the hInstance used to create the dialog box.

Edit controls created with CreateWindow() use the data segment pointed to

by hInstance.

The GLBEDIT sample shows how to change hInstance to point to a new global

object. Multiple controls of any type can use the same memory object.

To find the effected portions of the code, search for WM_CREATE in the

MainWndProc.

Additional reference words: 3.00 3.10 softlib GLBEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


Sample Source Code Demonstrates Playing Metafiles

Article ID: Q77649

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

----------------------------------------------------------------------

PLAYMETA is a file in the Microsoft Software Library that demonstrates

techniques an application can use to open a metafile and "play" it

into a device context.

PLAYMETA can also be used to help identify errors in a given metafile

because it pauses and displays a message box before acting on each

record.

Download PLAYMETA.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PLAYMETA.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PLAYMETA.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PLAYMETA.EXE

Additional reference words: 3.00 3.10 softlib PLAYMETA.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiMeta


SAMPLE: Modal Dialog Child of Modeless Dialog Box Sample Code

Article ID: Q77783

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

MDLMDLS is a file in the Microsoft Software Library that demonstrates how

to create a modal child of a modeless dialog box. The sample uses two

modeless dialog boxes. However, when the second dialog is created, the

first dialog and the main application window are disabled.

Download MDLMDLS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MDLMDLS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MDLMDLS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MDLMDLS.EXE

Additional reference words: 3.00 3.10 softlib MDLMDLS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


Sample Help File Demonstrates Win 3.1 Help Macros

Article ID: Q77931

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

In Windows 3.1, there are a number of macros available that can be

used by the writer of help systems to enhance an application's help

files. MACROHLP was written to demonstrate each of the macros that can

be used by the person writing help files. The RTF source files are

also included in MACROHLP as examples for the person authoring help

files to follow.

MACROHLP is one of the Advanced Samples provided with the Windows

Software Development Kit (SDK), version 3.1.

Download MACROHLP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MACROHLP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MACROHLP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MACROHLP.EXE

Additional reference words: 3.10 softlib MACROHLP.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsHlp


SAMPLE: DDEML with Metafiles

Article ID: Q78807

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

DDEMETA is a file in the Microsoft Software Library that contains the

source code to an application that demonstrates how to read a Windows

metafile and pass the information using dynamic data exchange (DDE).

Download DDEMETA.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for DDEMETA.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DDEMETA.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DDEMETA.EXE

The remainder of this article explains how to use DDEMETA.

MORE INFORMATION

================

DDEMETA is a server application that uses the Dynamic Data Exchange

Management Library (DDEML).

To use DDEMETA, perform the following five steps:

1. Start DDEMETA.

2. Choose DDE Init from the Sample menu to register DDEMETA with the

   DDEML.

3. Start a DDE client application to initiate a conversation with

   DDEMETA. In the client, use the application name "DDEMETA" and the

   topic "Test".

4. After the conversation is established, the client application can

   request any "item" of type CF_METAFILEPICT from the server.

5. When DDEMETA receives the request, it will read the TEST.WMF file

   from the disk and pass it to the client application.

To test DDEMETA, request a CF_TEXT item. Note that the "item"

reference is never checked; therefore, any item name works.

Note: This program will not read "placeable" metafiles. For more

information on "placeable" metafiles, query on the following words in

the Microsoft Knowledge Base:

   placeable

Additional reference words: 3.10 softlib DDEMETA.ZIP

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Code Demonstrates Using Dialog Box Templates

Article ID: Q78953

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

DIALOG is a file in the Microsoft Software Library that demonstrates how to

create a dialog box template to use with the CreateDialogIndirect()

and DialogBoxIndirect() functions.

DIALOG includes a collection of functions that can be included in

another application to assist in the process of creating the dialog.

DIALOG also includes a test program that can be used to display the

dialog on the screen.

Download DIALOG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DIALOG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DIALOG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DIALOG.EXE

Additional reference words: 3.00 3.10 softlib DIALOG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Code Demonstrates an Application Sign-On Screen

Article ID: Q79976

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.o and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Many applications have a "sign-on" screen that is displayed while the

application is loading and initializing. This screen remains visible

for some set amount of time or until the user performs some action

that interacts with the application. At that point, the sign-on screen

disappears and the application may be used as normally.

Download SIGNON.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SIGNON.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SIGNON.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SIGNON.EXE

The sign-on screen can be implemented by using a modeless dialog box

and performing some additional processing in the application's main

message loop. After the main window is created and displayed, a

modeless dialog box is created and displayed. This modeless dialog box

usually contains the company name and application copyright

information. The application then waits for any action indicating that

the user is ready to work, such as clicking the mouse or typing on the

keyboard. Additionally, the application could start a timer and remove

the sign-on screen after a set amount of time (five seconds, for

example).

Additional reference words: 3.00 3.10 softlib SIGNON.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Code Demonstrates Using TrackPopupMenu

Article ID: Q80225

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Under Windows version 3.1, the TrackPopupMenu() function documents and

uses its last parameter. This parameter is an LPRECT, which describes

the rectangle in which the user can release the mouse button without

dismissing the menu.

This newly documented parameter is useful for applications that

display a pop-up menu in response to a WM_LBUTTONDOWN message. When

using this parameter, it is not necessary to hold down the mouse

button until a menu selection is made. The user can release the button

and select an item from the menu with a second button click.

TRACKPOP is a file in the Microsoft Software Library that demonstrates

using the TrackPopupMenu function.

Download TRACKPOP.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TRACKPOP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TRACKPOP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TRACKPOP.EXE

Additional reference words: 3.10 softlib TRACKPOP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: Spawn an Application and Wait Sample Code

Article ID: Q80226

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

ARNIE is a file in the Microsoft Software Library that demonstrates how

an application designed for the Windows environment can spawn another

application and suspend its execution until the spawned application

terminates. The sample application demonstrates detecting when a task

starts and completes using the TOOLHELP.DLL dynamic-link library, a

new feature of Windows 3.1.

Download ARNIE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ARNIE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ARNIE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ARNIE.EXE

MORE INFORMATION

================

The TOOLHELP DLL supplies a notification mechanism by which an application

can be notified of various events that occur in the system. Two such events

are task startup and task termination. To install a notification hook, the

application calls the NotifyRegister() function, specifying a callback

procedure. The callback procedure is called when specified events occur in

the system. To determine when an application starts and ends, watch for the

NFY_TASKSTART and NFY_TASKEND notifications in the callback procedure. When

the application no longer requires notifications, call NotifyUnRegister().

Additional reference words: 3.10 softlib ARNIE.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: Capturing and Reproducing Ink

Article ID: Q80360

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

REPAINT is a file in the Microsoft Software Library that demonstrates how

an application can capture "ink" that a user writes in the application's

window and reproduce the ink at a later time with the same appearance.

Download REPAINT.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for REPAINT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download REPAINT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get REPAINT.EXE

MORE INFORMATION

================

The REPAINT sample application uses the RedisplayPenData() function to draw

the ink. REPAINT also demonstrates how the size of ink can change as the

size of the application window changes.

REPAINT includes a README.TXT file that provides additional details about

the ink storage and reproduction process.

Additional reference words: 1.00 softlib REPAINT.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenInk


SAMPLE: Changing Size of an Edit Control

Article ID: Q80553

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

EXPEDIT is a file in the Microsoft Software Library that demonstrates

changing the size of an edit control in response to an EN_UPDATE message.

In the sample, when the typed text reaches the end of a line, the edit

control expands to allow the user to continue typing on a new line.

Download EXPEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EXPEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EXPEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EXPEDIT.EXE

MORE INFORMATION

================

Windows sends the EN_UPDATE notification message to the parent of the edit

control whenever the contents of the edit control have been altered, but

before the display is updated. The notification is sent to the parent

window as the HIWORD of the lParam parameter of a WM_COMMAND message. The

ID of the control is in the wParam.

Therefore, for an application to determine when it is necessary to change

the size of the edit control, it must handle the WM_COMMAND case in which

the wParam is the ID of the control and the HIWORD of the lParam is

EN_UPDATE. When EXPEDIT receives an EN_UPDATE notification message, it

performs the following eight actions:

1. Sends an EM_FMTLINES message to the edit control (wParam = 1). When

   the control processes this message, it modifies its buffer to have

   the character sequence carriage return-carriage return-linefeed

   (CR-CR-LF) at the end of each line.

2. Retrieves the length of the edit control's buffer.

3. Passes a handle to the (nonempty) buffer of the DrawText() function,

   which calculates the size of the rectangle required to hold all the

   text.

4. Adjusts the text height returned by DrawText because DrawText

   interprets the CR-CR-LF sequence at the end of each buffer line as

   two lines instead of one.

5. Compares the right edge of the rectangle returned from DrawText with

   the "limit." DrawText will extend the right edge of the rectangle

   if the text is too long. If the right edge of the last line exceeds

   the limit, then the edit control needs an additional line. EXPEDIT

   performs all the obvious limit checks.

6. If the height has not changed, then it is not necessary to change

   the size of the edit control, and EXPEDIT returns. Otherwise,

   the size of the edit control must be changed.

7. Updates the size of the edit control with MoveWindow() and

   UpdateWindow().

8. Returns FALSE so that the Dialog Manager will not do anything when

   it receives the EN_UPDATE message.

NOTE: The key idea of this implementation is to "predict" whether the next

character will fit in the edit control; if it will not, then add a new line

to the control so that the character will fit. This prediction is

accomplished by subtracting the width of "W" from the edge of the edit

control's rectangle to get the limit.

Additional reference words: 3.00 3.10 softlib EXPEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Preventing Windows from Switching Tasks

Article ID: Q80822

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Certain types of applications, such as security applications and possibly

some setup programs, require the ability to disable task switching under

Windows. To disable task switching, the program must prevent the user from

accessing the Task List, using mouse or keystroke combinations to switch to

other applications, and so forth.

The NOSWITCH application in the Microsoft Software Library demonstrates how

an application can disable the task switch.

Download NOSWITCH.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for NOSWITCH.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NOSWITCH.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NOSWITCH.EXE

MORE INFORMATION

================

NOSWITCH demonstrates how an application can disable task switching. The

application must take the following four steps to disable task switching:

1. Subclass the desktop window to prevent the Task List from being

   displayed when the user double-clicks the desktop window.

2. Prevent the user from using key combinations to switch to another

   task by trapping the following three wParam values for the

   WM_SYSCOMMAND message: SC_NEXTWINDOW, SC_PREVWINDOW, and

   SC_TASKLIST.

3. Prevent other applications from activating themselves by

   enumerating all top-level windows, and disabling the windows that

   do not belong to this application.

4. Each time a WM_INITMEMUPOPUP message is received for the system

   menu, disable the menu items that relate to switching tasks.

Before exiting the application, reverse the effects of any actions taken to

prevent switching tasks. Refer to the NOSWITCH sample for complete details.

There is a simpler, more limited, method to disable task switching. If the

application is run as a maximized window, then step 2 above is enough to

prevent switching tasks. However, the application must prevent the window

from being restored or minimized. The limitation to this method is that the

application must run as a maximized window.

Additional reference words: 3.00 3.10 softlib NOSWITCH.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Switching Between Accelerator Tables in an Application

Article ID: Q80887

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In some cases, it is useful to change the accelerator keys that are

assigned to menu items in an application. CHGACCL is a sample in the

Microsoft Software Library that demonstrates changing the accelerators by

loading a different accelerator table from the RC file and modifying the

text of menu items.

Download CHGACCL.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for CHGACCL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CHGACCL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CHGACCL.EXE

CHGACCL has two accelerator tables defined in the .RC file and a menu item

that allows the user to "swap" accelerator tables. When the user chooses to

swap the accelerators, the application loads the second accelerator table

and modifies the menu to reflect the changes in the accelerators. The user

can swap back to the original accelerator table by choosing swap

accelerators from the menu a second time.

DYNACCEL is a second sample in the Microsoft Software Library that

demonstrates building an accelerator table as part of an application.

Download DYNACCEL.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DYNACCEL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DYNACCEL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DYNACCEL.EXE

NOTE: Two (or more) instances of the application can be running, using

different accelerators for each instance.

CHGACCL also uses specific GDI functions to properly draw shapes in the

client area of the window. Each time the user chooses a new shape from the

menu, the client area device context is reset to properly define the

window's background color, pen color, mapping mode, and compression

factors.

Additional reference words: 3.00 3.10 softlib CHGACCL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: Implementing a Read-Only Edit Control In Windows

Article ID: Q80946

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In some situations, an application may contain text that is displayed for

the user to read, which is undesirable for the user to modify. The

application can use a static control to contain this text if the message is

short. However, for larger amounts of text, which require scrolling to

display all the text in the allotted area, something closer to an edit

control is required. This article, and its associated sample code, details

how to make an edit control "read- only."

ROEDIT is a file in the Microsoft Software Library that demonstrates the

techniques discussed in this article.

Download ROEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ROEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ROEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ROEDIT.EXE

MORE INFORMATION

================

An application can create a read-only edit control by subclassing or

superclassing a standard edit control. The subclass procedure filters out

messages that change the contents of the edit control. The following code

fragment demonstrates this process:

   FARPROC gOldProc;

   LONG FAR PASCAL ROEditProc(HWND hWnd, WORD msg,

                              WORD wParam, LONG lParam)

   {

       switch (msg)

       {

           case WM_KEYUP:

           case WM_KEYDOWN:

           case WM_CHAR:

           case WM_CUT:

           case WM_COPY:

           case WM_PASTE:

           case WM_LBUTTONUP:

           case WM_LBUTTONDOWN:

           case WM_LBUTTONDBLCLK:

               return 1L;

           case WM_GETDLGCODE:

               return 0L;

       }

       return CallWindowProc(gOldProc, hWnd, msg, wParam, lParam);

   } //*** ROEditProc

In the example above, the subclass procedure traps mouse clicks,

keystrokes, and the cut, copy, and paste commands. It also traps the

WM_GETDLGCODE message to prevent an edit control in a dialog box from

receiving the input focus.

The following example demonstrates superclassing an edit control to create

a new ROEDIT-class control that behaves similar to a read-only edit

control. A ROEDIT control implements the window procedure provided above.

It also changes the cursor to an arrow instead of an I-beam, which provides

an additional indication to the user that the contents of the control

cannot be changed. Using an ROEDIT control eliminates the necessity of

subclassing each control after it is created. When the application creates

a control from the ROEDIT class, the read-only behavior is provided

automatically.

The following code demonstrates superclassing an edit control as described

above:

   FARPROC gOldProc;

   BOOL RegisterROEdit(HANDLE hInstance)

   {

       WNDCLASS wc;

       if (!GetClassInfo(NULL, "EDIT", &wc))

           return FALSE;

       gOldProc = (FARPROC)wc.lpfnWndProc;

       wc.style        &= ~CS_GLOBALCLASS;

       wc.lpfnWndProc   = ROEditProc;

       wc.hInstance     = hInstance;

       wc.hCursor       = LoadCursor(NULL, IDC_ARROW);

       wc.lpszClassName = "ROEDIT";

       return RegisterClass(&wc);

   } //*** RegisterROEdit

In Windows 3.1, there is a new style bit for the edit control (ES_READONLY)

that removes the editing capabilities of the edit control, leaving only the

viewing capabilities. This style is useful when the application shows the

user a body of static text that the user reads and does not modify.

Additional reference words: 3.00 3.10 softlib ROEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Code Demonstrating Background Processing in Windows

Article ID: Q81139

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

There are often times when it is necessary for an application to execute a

time consuming process such as printing, file I/O, and math calculations in

the background. Doing so allows the Windows environment to continue to

service other applications while completing a lengthy process. BKGND is a

file in the Microsoft Software Library that demonstrates using a

PeekMessage() loop to perform background processing.

Download BKGND.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download SS13302.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BKGND.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BKGND.EXE

MORE INFORMATION

================

The BKGND sample application uses the WaitMessage() function, which allows

the application to "sleep" when the background process is complete. In the

sample, the user determines when background processing starts and ends. In

a production application, an application would probably determine when

background processing was required.

Additional reference words: 3.00 3.10 softlib BKGND.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMsg


SAMPLE: Code Demonstrates SystemParametersInfo()

Article ID: Q81140

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Version 3.1 of the Windows SDK documents a new function that allows an

application to change most of the system settings. An application can

retrieve and change settings as varied as the wallpaper on the desktop to

the width of window borders using the SystemParametersInfo() function.

SYSPARAM is a file in the Microsoft Software Library that demonstrates

using the SystemParametersInfo() function to retrieve and to change various

parameters.

Download SYSPARAM.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SYSPARAM.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SYSPARAM.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SYSPARAM.EXE

NOTE: SYSPARAM modifies the WIN.INI file. Make a backup copy of WIN.INI

before using this sample.

Additional reference words: 3.10 softlib SYSPARAM.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrSys


SAMPLE: DeviceCapabilities Function Sample Code

Article ID: Q81245

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

PRNDRV is a file in the Microsoft Software Library that demonstrates all

the options of the DeviceCapabilities() function provided by printer

drivers in the Windows 3.1 environment. PRNDRV retrieves printer

information and displays it on the screen.

Download PRNDRV.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PRNDRV.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PRNDRV.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PRNDRV.EXE

The DeviceCapabilities() function provides information about the

following printer features:

 - Information about the printer driver (driver size, driver date,

   driver version)

 - Information about the paper (paper sizes, paper extents, and so

   forth)

 - Information about the paper bins (bin numbers, bin types, named

   bins, and so forth)

 - Information from the DEVMODE structure (all header and device-

   independent information)

Additional reference words: 3.10 softlib PRNDRV.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


SAMPLE: Code Demonstrates Windows 3.1 WH_MOUSE Hook

Article ID: Q81333

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

MOUSHOOK is a file in the Software Library that demonstrates

installing and using a WH_MOUSE mouse message hook. The mouse message

hook in MOUSHOOK disables the right mouse button for all applications

in the system by discarding WM_RBUTTONDOWN and WM_NCRBUTTONDOWN

messages. The mouse hook function beeps each time it discards a

message.

The MOUSHOOK file contains the source to an application program,

TESTAPP, and a dynamic-link library (DLL), MOUSHOOK, that implements

the mouse hook. The MOUSHOOK DLL uses the new hook functions provided

by Windows 3.1: SetWindowsHookEx(), UnhookWindowsHookEx(), and

CallNextHookEx().

TESTAPP calls MOUSHOOK to install the mouse hook. When TESTAPP is

closed, it removes the mouse hook from the system.

Download MOUSHOOK.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MOUSHOOK.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MOUSHOOK.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MOUSHOOK.EXE

Additional reference words: 3.10 softlib MOUSHOOK.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrHks


SAMPLE: Code Demonstrates Using a WH_KEYBOARD Hook

Article ID: Q81334

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

KBHOOK2 is a file in the Software Library that contains sample

code to demonstrate installing and using a system-wide WH_KEYBOARD

keyboard filter function (otherwise known as a keyboard hook

function). This code monitors the status of the CAPS LOCK key.

Whenever the CAPS LOCK key is pressed, its status is displayed on the

application's icon. Terminating the application removes the keyboard

filter from the system.

KBHOOK2 updates the KBHOOK sample to use new functions provided by

Windows 3.1. For more information on the KBHOOK sample, query on the

following words in the Microsoft Knowledge Base:

   kbhook

Download KBHOOK2.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for KBHOOK2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download KBHOOK2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get KBHOOK2.EXE

MORE INFORMATION

================

KBHOOK2 contains an application program, KEYAPP, and a dynamic-link

library (DLL), KEYHOOK, that implements the keyboard filter function.

The KEYHOOK DLL uses the new Windows 3.1 hook functions:

SetWindowsHookEx, UnhookWindowsHookEx, and CallNextHookEx.

KEYAPP calls KEYHOOK to install the keyboard filter function and then

makes itself iconic. Windows calls KEYHOOK each time a key is pressed.

When the CAPS LOCK key is pressed, KEYHOOK posts a message to KEYAPP.

KEYAPP processes the message by painting its icon to display the

current state of CAPS LOCK. When KEYAPP is terminated, the KEYHOOK

filter is removed from the system.

NOTE: Compiling this sample as is will fail with the error that the include

file CONVDLL.INC cannot be found. To correct the problem, simply remove the

line

   INCLUDE CONVDLL.INC

from the LIBENTRY.ASM.

Additional reference words: 3.10 softlib KBHOOK2.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrHks


SAMPLE: Code Demonstrates Multiple Instance DLL

Article ID: Q81335

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

A dynamic-link library (DLL) in the Windows environment has a single

data segment that is used by each task (application instance) that

links to the DLL. However, there are many situations in which a DLL

must maintain data for each individual task. This article discusses

the method used by the MULTINST sample application to create a

multiple instance DLL. The DLL creates a separate data segment for

each task that links to it.

Download MULTINST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MULTINST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MULTINST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MULTINST.EXE

MORE INFORMATION

================

Because each task in the system has a separate stack segment, the

value of the stack segment can be used as a unique identifier.

MULTINST stores data for each task in a block of memory obtained using

GlobalAlloc(). Each time a task calls the DLL, use the value of its

stack segment as an index into the table of selectors for the global

memory blocks. Load the corresponding selector into the DS register.

After this is done, all static data and the local heap correspond to

the calling task.

When a new task calls into the DLL for the first time, the DLL

allocates a new block of memory to hold data for the task. It copies

initial values for static variables into the data block, and

initializes a local heap.

When a task that uses the DLL shuts down, it calls the UnregisterTask()

function in the DLL, which frees the data block associated with the task

and removes the task from the DLL's task list. Failing to call

UnregisterTask() might cause serious problems because Windows could

reassign a stack segment value to a new task. If this task called the DLL,

it would receive the data values associated with the previous task, which

might be completely inappropriate.

Place the following six lines of code at the beginning of each

function exported by the DLL to load the correct data segment:

   if ((wDS = LoadInstanceData()) == 0) // Get DS for this instance

      return;                           // If DS==0 then out of memory

   _asm {

        mov     ax,wDS

        mov     DS,ax

        }

The following text describes each function in the MULTINST DLL:

AddTask(): Allocate data for the task, initialize the data, and add the

           task to the task list.

FillHeap(): Allocate memory in the local heap until LocalAlloc fails.

            Used to demonstrate that the local heap will grow.

InitInstanceData(): Save initial values of static variables and

                    initialize the task list.

LibMain(): Save the initial values of static variables and the initial

           size of the data segment and the heap.

LoadInstanceData(): Retrieve the segment address (selector) to the data

                    for the task that called the DLL.

LookUpTask(): Given the value of the stack segment for the task, look up

              the segment address (selector) for the data for the task.

              If the task is not in the list, this function returns zero.

StoreData(): Save a string in the local heap.

WEP(): Required by a DLL.

Additional reference words: 3.00 3.10 softlib MULTINST.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: Code Extracts and Displays Application Resources

Article ID: Q81336

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

There are situations in which an application extracts information from

another application's executable image file without loading the other

application. The Microsoft Windows Program Manager does this when it

extracts an icon from an .EXE file to represent the application.

.EXE (and DLL) files contain many resources and tables that may be useful

in various circumstances. The EXEVIEW sample application demonstrates how

to extract and decode these resources from application and library

executable image files.

Download EXEVIEW.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EXEVIEW.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EXEVIEW.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EXEVIEW.EXE

NOTE: Because EXEVIEW uses code from the common dialog boxes dynamic-link

library (COMMDLG.DLL), version 3.1 of the Microsoft Windows SDK is required

to build the sample. However, EXEVIEW will run under either Windows version

3.0 or 3.1 provided that the COMMDLG.DLL file is installed.

MORE INFORMATION

================

EXEVIEW uses the information in both the Old Executable Header and the New

Executable Header, each of which are documented in "The MS-DOS

Encyclopedia" (Microsoft Press). EXEVIEW loads both headers and all the

tables to which they refer. These tables include: the entry table, the

segment table, the resource table, the resident and nonresident name

tables, and the imported name table. EXEVIEW loads the resources listed in

the resource table and displays them. Windows resources (icons, cursors,

bitmaps, menus, and so forth) are displayed graphically. String tables and

resource directories (of icons, cursors, fonts, and so forth) are listed in

text format.

For more information on the file formats and resource formats, see the

Windows SDK "Programmer's Reference, Volume 4: Resources," "The MS-DOS

Encyclopedia," the September, 1991, issue of the "Microsoft Systems

Journal," or the Microsoft Open Tools documentation.

Additional reference words: 3.10 softlib EXEVIEW.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrRsc


SAMPLE: Common Dialogs and Printing Functions Sample Code

Article ID: Q81337

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

PRNCDLG is a file in the Microsoft Software Library that demonstrates using

the new printing functions available in Windows 3.1. The sample

demonstrates the SetAbortProc(), StartDoc(), EndDoc(), StartPage(), and

EndPage() functions.

The sample also demonstrates using the ChooseFont() and PrintDlg() common

dialog boxes provided by the common dialog box library. The sample allows

the user to select a font and display a line of text to the screen using

that font. Also, the user can print the same line of text to a printer

selected through the PrintDlg() common dialog box.

Download PRNCDLG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PRNCDLG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PRNCDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PRNCDLG.EXE

Additional reference words: 3.10 softlib PRNCDLG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCmnDlg


SAMPLE: DIBs and Their Uses

Article ID: Q81498

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The following is the text of the article "DIBs and Their Uses". This

article is available in Windows Help file format in the Microsoft Software

Library in addition to the text presented below.

DIBS2.EXE can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DIBS2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735

      Download DIBS2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DIBS2.EXE

                          DIBs and Their Uses

                             by Ron Gery

ABSTRACT

========

This article discusses the DIB (device-independent bitmap) concept from

definition and structure to the API that uses it. Included is a small

sample application that illustrates some of the most common methods of

using DIBs to display and manipulate digital images. Functions discussed

are GetDIBits(), SetDIBits(), CreateDIBitmap(), SetDIBitsToDevice(),

StretchDIBits(), and CreateDIBPatternBrush(). This article does not discuss

using palettes with DIBs.

OVERVIEW

========

A DIB (device-independent bitmap) is a format used to define device-

independent bitmaps in various color resolutions. The main purpose of DIBs

is to allow bitmaps to be moved from one device to another (hence, the

device-independent part of the name). A DIB is an external format, in

contrast to a device-dependent bitmap, which appears in the system as a

bitmap object (created by an application using CreateBitmap(),

CreateCompatibleBitmap(), CreateBitmapIndirect(), or CreateDIBitmap()). A

DIB is normally transported in metafiles (usually using the StretchDIBits()

function), BMP files, and the Clipboard (CF_DIB data format).

A DIB consists of two parts: the bits themselves and a header that

describes the format of the bits. The header contains the color format, a

color table, and the size of the bitmap. The current DIB format supports

four color resolutions: 1 bit, 4 bit, 8 bit, and 24 bit. In 1-bit, 4-bit,

and 8-bit DIBs, the pixels are defined by indexes (of the appropriate bit

resolution) into the color table; 24-bit pixels are described as 24-bit

values, 1 byte each for red, green, and blue.

The DIB functions are:

   GetDIBits           Translates a device-dependent bitmap into the DIB

                       format

   SetDIBits           Translates a DIB's information into device-

                       dependent form

   CreateDIBitmap      Creates a device-dependent bitmap initialized with

                       DIB information

   SetDIBitsToDevice   Sets a DIB directly to the output surface

   StretchDIBits       Moves a rectangle from the DIB to a rectangle on

                       the destination surface, stretching or compressing

                       as necessary

   CreateDIBPatternBrush

                       Creates a pattern brush using a DIB for the bitmap

                       description

DEVICE INDEPENDENCE - WHAT'S IT GOOD FOR?

=========================================

Transferring color bitmaps from one device to another was not possible in

versions of the Microsoft Windows graphical environment earlier than 3.0.

With DIBs, each device displays the image to the extent of its color

resolution. An application can store an image in the DIB format and then

display it, regardless of the output device; an application need no longer

create a version of each image for each type of device.

This image transfer ability can be used to print halftone images. For

example, the StretchDIBits() function can pass a DIB directly to an

intelligent printer driver. Given the full color information of the image

instead of simply a monochrome version (the traditional method), the driver

can use halftones to print a realistic picture.

Because the DIB format is publicly defined, an application can manipulate

it on the fly. In fact, an application can build an image without any

interaction with Windows. If Windows lacks a drawing primitive, the

application can simulate it directly into the DIB instead of using the

existing graphics device interface (GDI) primitives. Unfortunately, under

Windows versions 3.0 and 3.1, GDI cannot perform output operations directly

to a DIB.

BMP FILE FORMATS

================

The file extension of a Windows DIB file is BMP. The file consists of a

BITMAPFILEHEADER structure followed by the DIB itself. Unfortunately,

because the BITMAPFILEHEADER structure is never actually passed to the API,

not every application that generates BMP files fills out the data structure

carefully. To add to this confusion, the "proper" definition of the

structure is at odds with the documentation. Properly, the data structure

contains the following fields:

   bfType              A WORD that defines the type of file. It must be

                       'BM'.

   bfSize              A DWORD that specifies the size of the file in

                       bytes. The Microsoft Windows Software Development

                       Kit (SDK) documentation claims otherwise. To be on

                       the safe side, many applications calculate their

                       own sizes for reading in a file.

   bfReserved1,

   bfReserved2         WORDs that must be set to 0.

   bfOffBits           A DWORD that specifies the offset from the

                       beginning of the BITMAPFILEHEADER structure to the

                       start of the actual bits. The DIB header

                       immediately follows the file header, but the

                       actual image bits need not be placed next to the

                       headers in the file.

The DIB header immediately follows the BITMAPFILEHEADER structure.

For a code sample that reads a BMP file, see the sample program.

The DIB Header

--------------

The header actually consists of two adjoining parts: the header proper and

the color table. Both are combined in the BITMAPINFO structure, which is

what all DIB APIs expect.

Windows version 3.0 supports two varieties of headers: BITMAPINFOHEADER and

BITMAPCOREHEADER. If at all possible, applications should use only

BITMAPINFOHEADERs. The BITMAPCOREHEADER definition is based on the bitmap

definition from Presentation Manager version 1.1 and is supported for

compatibility.

During a DIB setting operation, most fields are already filled in by

whoever generated the DIB. Doing a GetDIBits() call, however, provides more

control. The way the header is filled in for this operation defines the

resulting DIB, particularly its color resolution.

BITMAPINFOHEADER contains the following fields:

   biSize              Should be set to sizeof(BITMAPINFOHEADER). This

                       field defines the size of the header (minus the

                       color table). If a new DIB definition is added, it

                       is identified by a new value for the size. This

                       field is also convenient for calculating a pointer

                       to the color table, which immediately follows the

                       BITMAPINFOHEADER.

   biWidth, biHeight   Define the width and the height of the bitmap in

                       pixels. They are DWORD values for future

                       expansion, and the code in Windows versions 3.0

                       and 3.1 ignores the high word (which should be set

                       to 0).

   biPlanes            Should always be 1. All DIB definitions rely on

                       biBitCount for color resolution definition.

   biBitCount          Defines the color resolution (in bits per pixel)

                       of the DIB. Only four values are valid for this

                       field: 1, 4, 8, and 24. New resolutions (16 bit,

                       for example) may be added in the future, but for

                       now only these four define a valid DIB. Choosing the

                       appropriate value when doing a GetDIBits is

                       discussed below. When performing a Set operation,

                       the value should already be defined for the bits.

   biCompression       Specifies the type of compression. Can be one of

                       three values: BI_RGB, BI_RLE4, or BI_RLE8. The most

                       common and useful choice, BI_RGB, defines a DIB in

                       which all is as it seems. Each block of biBitCount

                       bits defines an index (or RGB value for 24-bit

                       versions) into the color table. The other two

                       options specify that the DIB is stored (or will be

                       stored) using either the 4-bit or the 8-bit run

                       length encoding (RLE) scheme that Windows

                       supports. The RLE formats are especially useful

                       for animation applications and also usually

                       compress the bitmap. BI_RGB format is recommended

                       for almost all purposes. RLE versions, although

                       possibly smaller, are slower to decode, not as

                       widely supported, and extremely painful to band

                       properly.

   biSizeImage         Should contain the size of the bitmap proper in

                       bytes. I say "should" because the field is not

                       necessarily filled in. A call to GetDIBits to

                       generate a DIB fills in this field, but a DIB

                       created manually by an application might not have

                       this filled in. Calculating the size of a bitmap

                       is not hard:

                       biSizeImage = ((((biWidth * biBitCount) + 31)

                                      & ~31) >> 3) * biHeight;

                       The crazy roundoffs and shifts account for the

                       bitmap being DWORD-aligned at the end of every

                       scanline. When nonzero, this field tells an

                       application how much storage space the DIB's bits

                       need. The biSizeImage field really becomes useful

                       when dealing with an RLE bitmap, the size of which

                       depends on how well the bitmap was encoded. If an

                       RLE bitmap is to be passed around, the biSizeImage

                       field is essential.

   biXPelsPerMeter,

   biYPelsPerMeter     Define application-specified values for the

                       desirable dimensions of the bitmap. This

                       information can be used to maintain the physical

                       dimensions of an image across devices of different

                       resolutions. GDI never touches these fields. When

                       not filled in, they should both be set to 0.

   biClrUsed           Provides a way for getting smaller color tables.

                       When this field is set to 0, the number of colors

                       in the color table is based on the biBitCount

                       field (1 indicates 2 colors, 4 indicates 16, 8

                       indicates 256, and 24 indicates no color table). A

                       nonzero value specifies the exact number of colors

                       in the table. So, for example, if an 8-bit DIB

                       uses only 17 colors, then only those 17 colors

                       need to be defined in the table, and biClrUsed is

                       set to 17. Of course, no pixel can have an index

                       pointing past the end of the table.

                       Note: This field cannot be used during a GetDIBits

                       operation. GDI always fills a full-size color

                       table. The field is therefore more useful for

                       post-processing operations, when an application

                       trims down the contents of the DIB. If nonzero for

                       a 24-bit DIB, it indicates a table that the

                       application can use for color reference.

   biClrImportant      Specifies that the first x colors of the color

                       table are important to the DIB. If the rest of the

                       colors are not available, the image still retains

                       its meaning in an acceptable manner.

                       biClrImportant is purely for application use; GDI

                       does not touch this value. When this field is set

                       to 0, all the colors are important, or rather,

                       their relative importance has not been computed.

The color table immediately follows the header information. No color table

is defined for 24-bit DIBs. The table consists of an array of RGBQUAD data

structures. (The table for the BITMAPCOREINFO format is built with the

RGBTRIPLE data structure.) Red, green, and blue bytes are in reverse order

(red swaps position with blue) from the Windows convention. This is another

leftover from Presentation Manager compatibility.

The size of the color table depends on the biBitCount value (and can

be overwritten using the biClrUsed field; see above):

   if (!(nNumColors = biClrUsed))

   {

     if (biBitCount != 24)

          nNumColors = 1 << biBitCount;

   }

   nTableSize = nNumColors * sizeof(RGBQUAD);

Most DIBs floating around currently have biClrUsed set to 0, but if any

full-fledged DIB bashing is planned, it is a good idea to set it properly.

If biClrUsed is nonzero, a color table with 24-bit DIBs is possible. GDI

does not use this color table, but the application can use it to determine

the important colors used in the DIB.

All DIB functions include a wUsage parameter, which can affect the

definition of the color table. This article avoids using palettes with

DIBs, and thereby assumes that wUsage is always set to DIB_RGB_COLORS and

that the color table is therefore always composed of RGB values. When

DIB_PAL_COLORS is used, the color table consists of WORD values that are

indexes into the currently selected logical palette. (This topic is

discussed in detail in the "Using DIBs with Palettes" article.)

Bit Formats

-----------

The header defines the format of the bits, but all formats share the

following rules:

 - Every scanline is DWORD-aligned. The scanline is buffered to

   alignment; the buffering is not necessarily 0.

 - The scanlines are stored upside down, with the first scan (scan 0)

   in memory being the bottommost scan in the image. (See Figure 1.)

   This is another artifact of Presentation Manager compatibility. GDI

   automatically inverts the image during the Set and Get operations.

   Figure 1. (Embedded image showing memory and screen representations.)

 - 64K segment boundaries are not respected; scanlines can cross such

   boundaries (unlike the device-dependent bitmap format that is

   buffered to 64K boundaries).

Each format has the following specifics:

 - 1-bit DIBs are stored using each bit as an index into the color

   table. The most significant bit is the leftmost pixel.

-  4-bit DIBs are stored with each 4 bits representing an index into

   the color table. The most significant nibble is the leftmost pixel.

 - 8-bit DIBs are the easiest to store because each byte is an index.

 - 24-bit DIBs have every 3 bytes representing a color, using the same

   ordering as the color table. This format is especially tricky

   during processing because a 64K boundary can exist in the middle of

   a color triple -- a difficult condition that must be handled with care.

USING THE DIB API

=================

GetDIBits() and SetDIBits()

---------------------------

These two functions are used to convert device-independent bitmaps into

device-dependent bitmaps and vice versa. SetDIBits() converts a DIB to a

device-dependent bitmap, and GetDIBits() generates a DIB from a device-

dependent bitmap.

The device driver referenced by the hDC passed into both calls performs the

actual translation. Some device drivers may not have this functionality

(for example, a Windows version 2.0 driver or a primitive Windows version

3.0 driver). In this case, GDI simulates the translation, but only in

monochrome -- color information is converted to black and white. For the

most part, however, this is not a concern. All self-respecting display

drivers support this functionality, and only a few printer drivers do not

provide the translation, usually monochrome drivers for which the GDI

simulations suffice.

GetDeviceCaps(hDC, RASTERCAPS) returns a WORD value with flags set

indicating which DIB functions the driver supports. RC_DI_BITMAP indicates

support of GetDIBits() and SetDIBits(), RC_DIBTODEV indicates support of

SetDIBitsToDevice(), and RC_STRETCHDIB indicates support of

StretchDIBits(). Any function not supported can be simulated, although the

simulations are often not as useful as the real thing (mainly because color

information is lost). A device may be unable to support the full

functionality even if a bit is set. For example, a device could support

StretchDIBits but only for integral stretches. Unfortunately, an

application has no way to determine the completeness of the implementation.

In these cases, GDI simulates the function.

The parameters are the same for both GetDIBits() and SetDIBits():

GetDIBits(hDC, hBitmap, nStartScan, nNumScans, lpBits, lpBitmapInfo,

wUsage)

SetDIBits(hDC, hBitmap, nStartScan, nNumScans, lpBits, lpBitmapInfo,

wUsage)

hDC            The device context (DC) responsible for the translation

               operation. hDC must be compatible with the hBitmap

               parameter.

hBitmap        The device-dependent bitmap from which (Get) or to

               which (Set) the DIB will be translated. Because of how

               the simulation code operates, this bitmap should not be

               currently selected into any DC.

nStartScan,

nNumScans      Define the contents of lpBits. For example, a StartScan

               of 5 indicates that lpBits points to the fifth scan of

               the DIB. A NumScans of 14 indicates that lpBits points

               to 14 scans of the DIB. Normally, nStartScan is set to

               0 and nNumScans is set to biHeight to denote that the

               whole DIB is pointed to by lpBits.

lpBits         The actual bitmap of the DIB. The pixel information is

               pointed to by this parameter.

lpBitmapInfo   The header (with color table) defining the DIB. The

               height and width in this header must match the height

               and width of the hBitmap parameter (the translation is

               always 1-to-1). The color resolution of the DIB need

               not match that of hBitmap.

wUsage         For the purposes of this article, assume this to be

               DIB_RGB_COLORS, indicating RGB colors in the color

               table.

Using SetDIBits() is reasonably straightforward. A DIB is taken from

somewhere (for example, from the Clipboard or from a disk file) and is

converted to a bitmap object, which can then be selected into a DC and

blted to the screen for display. This is the simplest way to display a

DIB.

NOTE: For many printers that can do halftones, this method is not

preferred; StretchDIBits (discussed below) is far more useful.

The following is a simple display of a DIB to a DC (with no error

handling):

   HBITMAP hBitmap;

   HDC hMemDC;

   hBitmap = CreateCompatibleBitmap(hDC, (WORD)lpInfo->biWidth,

          lpInfo->(WORD)biHeight);

   hMemDC = CreateCompatibleDC(hDC);

   SetDIBits(hDC, hBitmap, 0, (WORD)lpInfo->biHeight, lpBits,

          lpBitmapInfo, DIB_RGB_COLORS);

   hBitmap = SelectObject(hMemDC, hBitmap);

   BitBlt(hDC, 0, 0, (WORD)lpInfo->biWidth, (WORD)lpInfo->biHeight,

          hMemDC, 0, 0, SRCCOPY);

   DeleteObject(SelectObject(hMemDC, hBitmap));

   DeleteDC(hMemDC);

Using GetDIBits() is more complex because the application can choose

what kind of DIB to generate. The size of the source bitmap regulates

the DIB's dimensions (a piece can be extracted by blting into a

smaller bitmap), but the application's need can dictate the color

resolution.

For GetDIBits() to work properly, the application needs to set the

following fields in the header:

   biSize = sizeof(BITMAPINFOHEADER)

   biWidth = (width of the bitmap)

   biHeight = (height of the bitmap)

   biPlanes = 1

   biBitCount = [desired color resolution (1, 4, 8, or 24)]

   biCompression = BI_RGB (For RLE information, see below.)

Also, the space allocated for the color table must be sufficient to

hold a full-size table:

   if (biBitCount != 24)

     nSizeTable = (1 << biBitCount) * sizeof(RGBQUAD)

   else

     nSizeTable = 0;

The space allocated for lpBits also needs to be large enough to hold

nNumScans of data. The call fills in the following fields of the

structure:

 - biSizeImage = size in bytes of the DIB data

 - Color table (for non-24-bit case) is filled with appropriate colors

 - lpBits is filled with the DIB data

If GetDIBits() is called with lpBits set to NULL, no bits are returned;

only biSizeImage and the color table are filled in. This option is

useful for DIBs with RLE and is not worthwhile for non-encoded DIBs.

The application's goals for the DIB determine what color resolution to

choose. The usual approach is to generate a DIB that preserves the

color information of the source device-dependent bitmap. Choosing a

lesser resolution results in a loss of color information, which is

usually undesirable. Always using 24-bit resolution is unnecessary,

however, because doing so adds no more color resolution if the source

has 8-bit or less resolution.

   BITMAP bm;

   // get information on bitmap

   GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);

   BitmapRes = bm.bmPlanes * bm.bmBitsPixel;

   if (BitmapRes == 1)

     biBitCount = 1;

   else if (BitmapRes <= 4)

     biBitCount = 4;

   else if (BitmapRes <= 8)

     biBitCount = 8;

   else

     biBitCount = 24;

The bitmap's resolution calculation must take into account that some

device-dependent bitmaps are planar (notably EGA and VGA). DIBs, on

the other hand, are always "packed pixel," with only 1 plane per pixel

(biPlanes = 1).

The nStartScan and nNumScans parameters (a residue of Presentation

Manager compatibility) are designed to be used for banding. If not

enough memory is available to load the entire DIB into memory in one

piece, lpBits can be made to point to only a portion of the bits.

Consider the following example:

   #define MAXREAD 5

   WORD ReadXScans(LPSTR, WORD);   // Read up to X scans; return

                                   // NumRead.

   LPSTR lpBits;                   // Points to a block of memory for

                                   // MAXREAD scans.

   LPBITMAPINFOHEADER lpInfo;

   WORD nStart, nNumRead;

   for (nStart = 0; nStart >= (WORD)lpInfo->biHeight; )

   {

     nNumRead = ReadXScans(lpBits, MAXREAD);

     SetDIBits(hDC, hBitmap, nStart, nNumRead,

          lpBits, lpInfo, DIB_RGB_COLORS);

     nStart += nNumRead;

   }

The Set code takes the given band, translates it, and puts the

translated band in its proper location, accounting at all times for

the upside-down nature of DIBs. Notice how biHeight does not change at

any time because the band is placed in the bitmap based on the height

of the full bitmap. nStart is based on the height of the full image

(defined by biHeight).

CreateDIBitmap()

----------------

The following code demonstrates calling CreateDIBitmap() with the usual

case:

   hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits, lpInfo,

                            wUsage);

This is equivalent to:

   hBitmap = CreateCompatibleBitmap(hDC, (WORD)lpInfo->biWidth,

             (WORD)lpInfo->biHeight);

   SetDIBits(hDC, hBitmap, 0, (WORD)lpInfo->biHeight, lpBits, lpInfo,

             wUsage);

GDI's implementation skips the SetDIBits() part if the third parameter

is not set with the CBM_INIT flag. This function makes for nice

shortcut coding of the conversion from DIB to device-dependent bitmap.

SetDIBitsToDevice()

-------------------

SetDIBitsToDevice() allows an application to set a DIB directly to a device

surface. Because this function is a holdout from early development, its

interface is not as polished as it could be. StretchDIBits() is a far more

powerful function than SetDIBitsToDevice(). StretchDIBits() does all that

SetDIBitsToDevice() does and has a nicer interface. SetDIBitsToDevice() is

limited in the way it handles metafiles because it does not scale, and

banding with the nStartScan and nNumScans parameters is nontrivial at best.

StretchDIBits() does not allow the banding.

The following code performs the SetDIBitsToDevice() functionality on the

full bitmap (no banding) using StretchDIBits:

   StretchDIBits(hDC, x, y, (WORD)lpInfo->biWidth,

          (WORD)lpInfo->biHeight, 0, 0, (WORD)lpInfo->biWidth,

          (WORD)lpInfo->biHeight, lpBits, lpInfo, DIB_RGB_COLORS,

          SRCCOPY)

Assuming that nStartScan is set to 0 and that nNumScans is set to

lpInfo->biHeight (that is, no banding), the function is basically a

BitBlt with SRCCOPY as the ROP and with a DIB as the source. SrcX and

SrcY are in the DIB's space and are therefore upside down in relation

to the DC (Y = 0 is at the bottom of the image).

Dealing with the upside-down DIB is tricky when doing a partial

setting. For example, if an application wants to get the bottom third

of a DIB that is w by h pixels to the device at (x, y), the call would

resemble the following:

   SetDIBitsToDevice(hDC, x, y, w, h/3, 0, h/3, 0,

          (WORD)lpInfo->biHeight, lpBits, lpInfo, DIB_RGB_COLORS);

A device-dependent bitmap would have a SrcY of 2h/3 for the bottom

third, but with the upside-down system of the DIB, a SrcY of h/3

points to the proper place relative to Windows coordinates.

StretchDIBits()

---------------

This function is the do-all darling for displaying a DIB on the

surface of a device. It is especially nice for metafiling and for

printing, for which the ability to stretch is important.

The one critical hole in the current implementation of StretchDIBits()

is that StretchDIBits() is supported by printer drivers and not by many

display drivers. Therefore, using this function repeatedly to stretch

a DIB to the screen is significantly slower than using SetDIBits (to

get a device-dependent bitmap) followed by repeated StretchBlt() calls.

The implementation of this function in GDI is very straightforward. If

the device driver can handle the call itself, it does. If not, and the

call is 1-to-1 and the device supports SetDIBitsToDevice(), the call is

converted to a SetDIBitsToDevice() call to the driver. (This works only

with SRCCOPY as the ROP.) If neither of these methods is possible,

CreateDIBitmap() is used to make a device-dependent version of the

bitmap, and StretchBlt is called to do the actual work.

The parameters for StretchDIBits() are basically the same as for

StretchBlt() (with the source hDC replaced by lpBits and lpInfo). This

function does not have the nStartScan and the nNumScans parameters of

the other DIB functions, so lpBits always points to the first scan of

the DIB.

When using this function for anything other than full bitmap

stretches, remember that all of the source coordinates (the ones

relating to the DIB) are in an upside-down system. The function will

appropriately flip the image, but the source rectangle is defined with

Y=0 at the bottom and extents going up. Fortunately, the x-coordinates

use the same conventions as Windows.

Printer drivers that do support this functionality (for example,

PSCRIPT and HPPCL) usually use a halftone algorithm to output good

color images. Therefore, maintaining DIBs at the highest meaningful

color resolution possible (usually 8 bit) is desirable even if the

output device is monochrome, because the color information is still

useful for good output. Unfortunately, most printer drivers do not

support any ROP other than SRCCOPY.

CreateDIBPatternBrush()

-----------------------

This function allows an application to create a pattern brush by

specifying a DIB instead of a device-dependent bitmap, as used in the

CreatePatternBrush() function. A brush created using this function is

used similar to any other brush. The DIB is turned into a

device-dependent bitmap at SelectObject() time for use by the device.

This brush resembles a standard pattern brush to the device.

DIBS IN THE CLIPBOARD

=====================

Two basic mechanisms for placing DIBs in the Clipboard are using the

CF_DIB data format or placing the DIB into a metafile and using the

CF_METAFILEPICT data format.

The CF_DIB format uses a packed DIB, in which the bits follow

immediately after the header and the color table. When reading or

creating a packed DIB, an application must properly calculate the size

of the color table to ensure that the bits are in the proper place.

Because all DIB functions expect the DIB as two pointers, one to the

header and one to the bits, the bits pointer must be calculated before

use. (For color table size computations, see the code sample in the

color table description above.)

The simplest way to place a DIB into a metafile is to use

StretchDIBits():

   hMetaDC = CreateMetaFile((LPSTR) NULL));

   StretchDIBits(hMetaDC, 0, 0, biWidth, biHeight, 0, 0, biWidth,

          biHeight, lpBits, lpInfo, DIB_RGB_COLORS, SRCCOPY);

   hMetafile = CloseMetaFile(hMF);

This approach generates a metafile that when played back displays the

DIB to the destination. This method also scales the image to fit the

current mapping scheme if needed. Using metafiles for transfer enables

even applications that are not DIB-aware to paste the contents of the

Clipboard without losing the DIB information.

RLE FORMATS

===========

When the biCompression field in a DIB's header is set to either BI_RLE4

(for biBitCount = 4) or BI_RLE8 (for biBitCount = 8), the image has been

run-length encoded. A description of the encoding schemes can be found in

the "Microsoft Windows Software Development Kit Reference Volume 2," in the

"BITMAPINFOHEADER" section of the "Data types and Structures" chapter. The

basic scheme involves compressing multiple, horizontally adjacent,

identical pixels into a run encoding. For example, 10 pixels of color index

17 are encoded as a run of length 10 and of index 17. Codes for end-of-scan

and for delta moves are also provided, in which an X and a Y offset are

provided for the next pixel.

This type of encoding usually compresses the bitmap and is also useful for

creating sprite-type animations, in which only a small part of an image

changes in each frame. The animation capabilities are accomplished by using

delta codes to limit the number of pixels actually being set. Pixels

skipped by a delta move are left untouched.

The main limitations of RLE DIBs are that an application can neither easily

determine the size of the bitmap in bytes nor point to a certain scanline

without decoding the bitmap from the first scan. The biSizeImage field is

useful in solving the first problem. Decoding, encoding, and generally

manipulating the RLE format is slower and more complicated than the

noncompressed (BI_RGB) format. Some applications -- for example, Paintbrush

-- refuse to read RLE DIBs. Although all APIs accept them, RLE DIBs will

probably not become a universally supported format. Also, because of the

relative rarity of these formats, some device drivers might not have fully

tested support for the encoding and decoding processes.

To generate an RLE DIB, GetDIBits() is called with biCompression set to the

desired type of encoding. The amount of memory needed to store the bits is

not easily computed. If GetDIBits() is called with lpBits set to NULL, the

amount of memory needed for the bits is returned in biSizeImage. A

subsequent call with lpBits pointing to a properly sized block of memory

returns an encoded bitmap.

Translating an RLE DIB into a device-dependent form requires no

special processing. Any of the Set functions can be used normally with

a header containing the proper biSizeImage and biCompression values to

match the bits.

SHORTCOMINGS OF DIBS

====================

Probably the biggest limitation of DIBs is that they are slower than device-

dependent bitmaps. Translating DIBs into a device-dependent form before

they can actually be displayed requires extra processing, resulting in

additional overhead. In an ideal world, a 1-to-1 StretchDIBits() would be

as fast as a BitBlt(). This speed would allow an application to operate

effectively in the realm of the logical bitmap, with full color and full

access to each and every pixel, regardless of the physical device's

limitations.

DIBs are based in a coordinate system that is upside down relative to

Windows, making coding a bit frustrating and not intuitive. Always

remembering this quirkiness should help limit the number of iterations

needed to get bitmaps properly lined up.

You can get full color using 24-bit DIBs, but they are very slow to decode,

read, and write. This is especially true on 8-bit palette devices, in which

translation literally can take minutes. Also, the sheer size of 24-bit DIBs

makes them a bit unwieldy for general use.

DIB-RELATED PROBLEMS IN WINDOWS VERSION 3.0

===========================================

Metafile recording of StretchDIBits() calls that use BITMAPCOREHEADER

causes a UAE. Convert all headers to the BITMAPINFO style to avoid this

problem. This workaround is recommended for general DIB processing.

The SetDIBits() simulation code for greater than 64K monochrome DIBs causes

crashes or erroneous printouts when using a SetDIBits(), a

SetDIBitsToDevice(), or a StretchDIBits() to a driver that does not support

SetDIBits().

Copyright 1992 by Microsoft Corporation.  All rights reserved.

Additional reference words: 3.00 3.10 softlib DIBS2.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Multiline Edit Control Overwrite Mode Sample Code

Article ID: Q81610

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

ECOVRWRT is a file in the Microsoft Software Library that demonstrates how

an

application can implement a multiline edit control in which the user can

toggle between "insert" mode and "overwrite" mode. In insert mode, new text

pushes any existing text further to the right. In overwrite mode, new text

replaces any existing text.

To implement overwrite mode, ECOVRWRT subclasses the multiline edit

control. When the control is in overwrite mode, when the control receives a

WM_CHAR message, the character after the selection point is selected and

replaced with the character in the wParam of the message.

Download ECOVRWRT.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for ECOVRWRT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ECOVRWRT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ECOVRWRT.EXE

Additional reference words: 3.00 3.10 softlib ECOVRWRT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Sample Code Demonstrates an Owner-Draw Combo Box

Article ID: Q81706

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

When Windows creates an owner-draw combo box, it sends WM_DRAWITEM messages

to the parent window of the combo box. To respond to this message, the

parent window must perform the steps necessary to draw the items in the

owner-draw combo box.

OWNCOMBO is a sample in the Microsoft Software Library that contains an

example of a fixed-height owner-draw combo box that contains strings. The

combo box also demonstrates painting bitmaps, changing the text color, and

storing data associated with each item using the CB_SETITEMDATA message.

All of the relevant code is contained within the ODDLG.C module.

Download OWNCOMBO.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for OWNCOMBO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download OWNCOMBO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get OWNCOMBO.EXE

Additional reference words: 3.00 3.10 softlib OWNCOMBO.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Code Implements a "Tool Box" Window

Article ID: Q81814

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Image Editor and the Dialog Editor are two applications provided with

the Windows SDK that demonstrate a "tool box" window. This article

discusses how to implement a tool box window in an application. TOOLBOX is

a file in the Microsoft Software Library that demonstrates the techniques

discussed.

Download TOOLBOX.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TOOLBOX.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TOOLBOX.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TOOLBOX.EXE

MORE INFORMATION

================

A tool box window contains a group of icons that the user can choose at any

time. The tool box window always floats above the application with which it

is associated.

The code in TOOLBOX assumes that all buttons in the tool box have the same

size and are equally spaced throughout the window. TOOLBOX implements the

following four steps to create the tool box window:

1. Loads the bitmap that provides the visual appearance for all the

   buttons.

2. Creates the tool box window with the WS_EX_TOPMOST style bit set.

   Sizes the window appropriately based on the size of the bitmap.

3. Processes the WM_ACTIVATE message in the window procedure for the

   application's main window. If the main window or the tool box

   window is being activated, TOOLBOX calls SetWindowPos() to add the

   WS_EX_TOPMOST style to the window. If a window other than the main

   window or the tool box window is being activated, TOOLBOX calls

   SetWindowPos() to remove the WS_EX_TOPMOST style from the window.

4. Performs the following two steps in the window procedure for the

   tool box window:

   a. Processes the WM_LBUTTONDOWN message. Performs hit testing to

      determine which button the user chose. To make the button appear

      depressed, TOOLBOX determines the rectangle for the button.

      TOOLBOX uses the InvertRect function to invert the colors of the

      button.

   b. Processes the WM_PAINT message. TOOLBOX uses the StretchBlt()

      function to paint the bitmap onto the window. If any button is

      depressed, TOOLBOX inverts the appropriate region as above.

Although this sample does not demonstrate every possibility for tool

box windows, the sample is very straightforward and easily modified.

Additional reference words: 3.10 softlib TOOLBOX.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Using mciSendCommand() to Control CD-ROM Drive

Article ID: Q81869

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

PLYCDNO is a file in the Microsoft Software Library that demonstrates using

Media Control Interface (MCI) functions provided by the Windows API to

control a CD-ROM (compact disk read-only memory) drive.

Functions in PLYCDNO play the CD, pause, move forward and backward by

tracks, determine the position within the CD, and eject the CD from

the drive.

Download PLYCDNO.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for PLYCDNO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PLYCDNO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PLYCDNO.EXE

Additional reference words: 3.00 3.10 softlib PLYCDNO.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMCDROM


SAMPLE: Controlling the CD Using mciSendCommand()

Article ID: Q81871

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

PLAYCD is a file in the Microsoft Software Library that demonstrates how an

application developed for Microsoft Windows can play a music CD (compact

disk) in a CD-ROM (compact disk read-only memory) drive. PLAYCD has two

parts: the PLAYCD application and the PLYCD dynamic-link library (DLL).

The PLAYCD application does very little by itself. It calls functions

in the PLYCD DLL to play the CD.

The PLYCD DLL contains code to control the CD-ROM player. PLYCD

includes functions to play the CD, pause, move forward and backward by

tracks, determine the position within the CD, and eject the CD from

the drive. PLYCD interacts with the Media Control Interface (MCI)

using the mciSendCommand() API.

Download PLAYCD.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for PLAYCD.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PLAYCD.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PLAYCD.EXE

Additional reference words: 3.10 softlib PLAYCD.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMCDROM


SAMPLE: Detecting Multimedia Extensions and Drivers

Article ID: Q81872

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows version 3.0

----------------------------------------------------------------------

NOMMDLL is a file in the Microsoft Software Library that demonstrates how

to determine whether the Multimedia Extensions to Microsoft Windows

and its associated drivers are installed. NOMMDLL has two parts: the

PLAYWAV application and the PLYSND dynamic-link library (DLL).

PLAYWAV indicates that the Multimedia Extensions are installed when

its Sound menu option is available. When this menu item is grayed or

unavailable, the Extensions are not installed. By default, PLAYWAV

also determines if the sound driver is loaded. You can modify the code

to look for other drivers if desired.

An application can use the PLYSND DLL to play sounds. The functions in

PLYSND are useful to control the Media Control Interface (MCI).

Download NOMMDLL.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for NOMMDLL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NOMMDLL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NOMMDLL.EXE

Note: NOMMDLL uses the LASER.WAV file distributed with the Multimedia

Extensions. To use NOMMDLL, verify that the MMDATA directory is listed

in the MS-DOS PATH environment variable, or copy the LASER.WAV file

into the same directory as NOMMDLL.EXE.

Additional reference words: 3.00 softlib NOMMDLL.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMMisc


SAMPLE: Controlling a Videodisc Player

Article ID: Q81993

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

PLYVIDEO is a file in the Microsoft Software Library that demonstrates

using Media Control Interface (MCI) functions to control a videodisc

player.

Functions in PLYVIDEO play the videodisc, pause, move forward and

backward through the disc by frames, retrieve position information,

and eject the videodisc.

Download PLYVIDEO.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for PLYVIDEO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PLYVIDEO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PLYVIDEO.EXE

Additional reference words: 3.10 softlib PLYVIDEO.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMVideo


SAMPLE: Program Demonstrates Edit Control Validation

Article ID: Q82076

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

DATAVAL is a file in the Microsoft Software Library that demonstrates how

to validate the contents of one or more edit controls within the same

dialog box without subclassing the edit controls.

Download DATAVAL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DATAVAL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DATAVAL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DATAVAL.EXE

DATAVAL processes the EN_KILLFOCUS message, which the dialog box

receives after an edit control has lost the input focus. When the

dialog box receives an EN_KILLFOCUS message, it calls a validation

function to determine if the contents of the control losing focus is

valid. If the contents is not valid, then the dialog box posts a user-

defined "not valid" message to itself. When the dialog box processes

the "not valid" message, it displays a message box alerting the user

of the error, and then sets focus back to the control with invalid

contents. A cancel button in the dialog box allows the user to exit

the dialog box without performing validation.

An application is in an unstable state when it receives an

EN_KILLFOCUS message; Windows is in the process of switching focus

between windows. Therefore, the application must use PostMessage to

provide the "not valid" message or the application can enter an

infinite loop.

Additional reference words: 3.00 3.10 softlib DATAVAL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


Sample Application Demonstrates Using DDEML

Article ID: Q82077

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

DMLDEMO is a file in the Microsoft Software Library that demonstrates how

two applications for the Windows environment can communicate using the

Dynamic Data Exchange Management Libraries (DDEML). DMLDEMO

demonstrates the following types of transactions:

 - Connect

 - Request

 - Asynchronous Request

 - Hot Advise Loop

 - Warm Advise Loop

Download DMLDEMO.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for DMLDEMO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DMLDEMO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DMLDEMO.EXE

NOTE: The DMLDEMO file contains code for a client application and for

a server application in separate directories. To preserve the

directory structure, be sure to specify the -d option when extracting the

files. For example,

   dmldemo -d

MORE INFORMATION

================

The remainder of this article details the five transaction types.

Connect Transaction

-------------------

The client calls the DdeConnect function to connect to the server and

initiate a conversation. In the DMLDEMO application, the DdeConnect

function starts a general conversation, which deals with text and

bitmaps, and a SYSTEM conversation, which supports the system topic.

Request Transaction

-------------------

When the client requires information from the server, the client calls

the DdeClientTransaction function, specifying XTYP_REQUEST as the

value for the uType parameter. The DMLDEMO client uses a request

transaction to retrieve the number and type of bitmaps to display. The

request transaction is used in both synchronous and asynchronous

contexts.

Asynchronous Transaction

------------------------

The client starts an asynchronous transaction with the server to

request information that may not be ready at the time the client makes

the request.

In the DMLDEMO application, the client starts an asynchronous

transaction when the user chooses Asynchronous Transaction from the

Transactions menu. When the server receives the request (as an

XTYP_REQUEST transaction), it displays a dialog box that asks the user

how many copies of the window bitmap the client should display. After

the user dismisses the dialog box, the server returns a data handle

containing the number the user selected from its callback function.

When the server has completed the transaction, the DDEML sends an

XTYP_XACT_COMPLETE to the client application's callback function. The

client then displays the requested number of bitmaps.

In this case, an asynchronous transaction is required to prevent the

transaction from timing out before the user has a chance to close the

dialog box.

Hot Advise Loop

---------------

When a hot advise loop is established between a client and a server,

the server notifies the client (through an XTYP_ADVDATA transaction)

each time a certain piece of data changes. The notification includes a

handle to the changed data. When a hot advise loop is active in the

DMLDEMO application, the server notifies the client that the bitmap

has changed (this notification includes a handle to the changed

bitmap) every time the server's bitmap is changed. (To change the

bitmap, choose Change Bitmap from the server application's menu.) The

client application then displays the bitmap.

Warm Advise Loop

----------------

When a warm advise loop is established between a client and a server,

the server notifies the client that the specified data has changed,

but the server does not send the changed data to the client. In the

DMLDEMO application, when the client receives a notification from the

server, the client brings up a message box asking the user if the

client's window should be updated with the new bitmap from the server.

If the user chooses the "Yes" button, the client requests the changed

bitmap from the server using the DdeClientTransaction function,

specifying XTYP_REQUEST as the value of the uType parameter.

Additional reference words: 3.00 3.10 softlib DMLDEMO.ZIP

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Code Demonstrates Creating Dialog Box in DLL

Article ID: Q82170

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

DLLDLG is a file in the Microsoft Software Library that demonstrates

creating a dialog box in a dynamic-link library (DLL). The DLL

contains a routine that calls the DialogBox function. After the user

types some text into an edit control in the dialog box and chooses the

OK button, the routine calls the MessageBox() function to display the

text.

Because a DLL has only one instance, it is not necessary to call the

MakeProcInstance() function for the dialog box procedure. The DLLDLG sample

demonstrates this by specifying the dialog box procedure's name in the

call to the DialogBox() function.

The DialogBox() function uses the value of its hInstance parameter to

locate the dialog box's resource template. For this reason, the

hInstance value must point to the module that contains the template.

For the DLLDLG sample, the hInstance value passed to the DialogBox()

function is the value of the hInstance parameter passed to LibMain().

Download DLLDLG.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLLDLG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLLDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLLDLG.EXE

Additional reference words: 3.00 3.10 softlib DLLDLG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: TrueType Functions and Structures

Article ID: Q82233

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

TTDMP is a file in the Microsoft Software Library that demonstrates using

the new TrueType functions provided by Windows 3.1. TTDMP demonstrates the

GetOutlineTextMetrics() and GetRasterizerCaps() functions. The sample

displays the contents of the OUTLINETEXTMETRIC, TEXTMETRIC, PANOSE, and

LOGFONT structures that describe a TrueType font.

TTDMP also demonstrates using the ChooseFont and Print dialogs

provided by the common dialog box dynamic-link library (DLL). The user

can choose a font and display a line of text in the chosen font. The

sample will print the same line of text to a printer chosen in the

Print common dialog box.

Download TTDMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TTDMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TTDMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TTDMP.EXE

Additional reference words: 3.10 3.10 softlib TTDMP.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiTt


SAMPLE: Code Displays 256-Color DIB on Standard VGA

Article ID: Q82903

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Windows 3.1 provides the DisplayDib function to display a 256-color

bitmap image on a standard (16 color) VGA display. DisplayDib reduces

the display resolution to 320x200 or 320x240 and centers the bitmap on

the screen, clipping the image as necessary.

DisplayDib was first provided by the Multimedia Extensions to Windows

version 1.0. It has been tested with, and is supported by, Window 3.1.

DISPDIB is a file in the Microsoft Software Library that contains a

dynamic-link library (DLL) with the executable code for the DisplayDib

function. DISPDIB also includes a header file and an import library

file.

Download DISPDIB.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DISPDIB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DISPDIB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DISPDIB.EXE

Additional reference words: 3.10 softlib DISPDIB.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Navigating a Windows Help File Topic Hierarchy

Article ID: Q83010

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

In many cases, a Windows Help file presents its information in a

hierarchy of topics. For example, the initial screen of a Help file is

a listing of the major topics in the file. Selecting a major topic

brings up a list of detail topics. Selecting a detail topic displays

its corresponding screen of information. The following diagram

illustrates a hierarchical table of contents:

                          Table_of_Contents

                                  |

                /-----------------+-----------------\

          Major_Topic_1     Major_Topic_2     Major_Topic_3

          /     |     \        /       \         /       \

    topic_1 topic_2 topic_3  topic_4 topic_5  topic_6 topic_7

An "Up" button in a Windows Help file provides a convenient method for

the user to move up the hierarchy. In a major topic, the Up button

displays the table of contents. In a detail topic, the Up button

displays the corresponding major topic. In the table of contents, the

Up button is disabled because the table of contents is the highest

point in the hierarchy.

An Up button and a "Back" button each perform different functions.

While the Up button displays the topic on the next higher level of the

hierarchy, the Back button returns to the topic previously viewed. In

the topic hierarchy, the previous topic can be above, below, or on the

same level.

UPHELP is a file in the Microsoft Software Library that contains the files

required to build a Help file that implements an Up button. The file

contains a graphic image of its title hierarchy. As the user navigates

through the file using topic jumps and browse sequences, the graphic

changes to indicate the position in the file.

Download UPHELP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for UPHELP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download UPHELP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get UPHELP.EXE

This article details the steps required to implement an Up button in a

Windows Help file to help navigate up the topic hierarchy.

MORE INFORMATION

================

There are two major steps to implementing an Up button:

1. Placing a button on the button bar.

2. Programming the button to perform the required jump.

Placing an Up Button on the Button Bar

--------------------------------------

A Help file adds a button to the button bar with the CreateButton

macro. Once a button is created, it will remain on the button bar

until a corresponding call is made to the DestroyButton macro. A file

can call macros in a topic footnote (which is described below) or in

the [CONFIG] section of the Help project (.HPJ) file. The following

code adds a button to the button bar:

   [CONFIG]

   CreateButton("Up_Button","&Up","JI(`uphelp.hlp',`Table_of_Contents')")

The added button has the identifier "Up_Button" and text "Up." When

the user presses this button, Help displays the "Table_of_Contents"

topic in the UPHELP.HLP file.

For more information on the CreateButton macro and on the [CONFIG]

section of the HPJ file, please consult the Windows Software

Development Kit (SDK) documentation for version 3.1.

Programming the Up Button

-------------------------

At the entry to each topic, it is necessary to change the topic that

Help displays when the user presses the Up button. Author an

exclamation point (!) footnote into each topic of the Help file. Help

executes the macros of an exclamation point footnote before it

displays a topic.

The macro for the table of contents topic is different from those in

the remainder of the Help file. Because the table of contents is the

top of the topic hierarchy, the Up button is disabled in the table of

contents topic. The text of the exclamation point footnote for the

table of contents topic contains the DisableButton macro.

The exclamation point footnote in the other topics in the Help file

contain two macros:

 - EnableButton, which is required because the topic previously

   displayed might have been the table of contents. (The user can use

   the Search feature to jump directly to a topic, bypassing the topic

   hierarchy.)

 - ChangeButtonBinding, which changes the action of the button.

Separate the text of the two macros with a semicolon (;).

The following text provides an example of an exclamation point

footnote. Note that in an actual Help file, the text below would not

contain any line breaks.

   ! EnableButton("Up_Button");

   ChangeButtonBinding("Up_Button",

                       "JI(`uphelp.hlp',`Table_of_Contents')")

The ChangeButtonBinding macro requires two parameters:

 - This first parameter is the button identifier, in this case

  "Up_Button".

 - The second parameter specifies the action of the button, in this

   case to call the JumpId (JI) macro. JumpID displays a specified topic

   in a specified Help file.

The Windows SDK documentation, version 3.1, provides additional

information about the following Help macros:

 - ChangeButtonBinding

 - CreateButton

 - DisableButton

 - EnableButton

 - JumpId (JI)

Additional reference words: 3.10 softlib UPHELP.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsHlp


SAMPLE: Reading and Converting Between the Three GDI Resources

Article ID: Q83034

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

GDIRSRCS is a file in the Microsoft Software Library that demonstrates the

following three techniques:

1. Reading a device independent bitmap (DIB) resource from a file and

   using that data to create one of the following:

    - A device dependent bitmap (DDB)

    - A cursor

    - An icon

2. Reading a cursor resource from a file and using that data to create

   one of the following:

    - A device dependent bitmap

    - A device independent bitmap

    - An icon

    - Another cursor

3. Reading an icon resource from a file and using that data to create

   one of the following:

    - A device dependent bitmap

    - A device independent bitmap

    - A cursor

    - Another icon

Download GDIRSRCS.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GDIRSRCS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GDIRSRCS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get GDIRSRCS.EXE

MORE INFORMATION

================

Reading icon and cursor resources from a file is straightforward.

However, reading a device independent bitmap resource from a file is

not so straightforward for the following two reasons:

 - The bitmap may be larger than 64K bytes. Therefore, an application

   must use a custom file-reading function that can deal with the

   64K-byte limit.

 - The device independent bitmap resource-file header has two

   different formats: one for OS/2 and another for Windows version 3.x.

   While the GDIRSRCS sample reads both formats, it stores bitmap

   information only in the Windows 3.x format.

Creating a Device Dependent Bitmap

----------------------------------

The process to create a DDB using the information in a DIB is

straightforward. Call the CreateBitmap() function to create a bitmap,

then read the image data from the DIB into the DDB.

Creating a DDB from a cursor or from an icon is also straightforward.

Note that a cursor and an icon each contain two bitmaps (the AND and

XOR bit masks) in a DIB. Extract the XOR bit mask and use it to create

a DDB.

In the GDIRSRCS sample, the functions that create bitmaps are in the

BMP.C file.

Creating a Cursor

-----------------

In the GDIRSRCS sample, the functions that create cursors are in the

CUR.C file.

The procedure to create a cursor based on a DIB obtained from a cursor

or icon resource file has eight steps. While the following discussion

describes the process of creating a cursor based on a DIB from an icon

file, the procedure to create a cursor based on a DIB from another

cursor is the same.

1. Obtain a pointer to the bits of the device independent bitmap from

   the icon.

2. Divide the height of the DIB by two because the DIB contains both

   the AND and XOR masks.

3. Calculate the offset to the AND mask bits.

4. Calculate the offset to the XOR mask bits.

5. Create a device dependent monochrome bitmap with the bits of the

   XOR mask.

6. Obtain the contents of the device dependent XOR bit mask and store

   it in memory. The AND bit mask is a monochrome bitmap. Because

   device independent and device dependent monochrome bitmaps share

   the same format, there is no need to convert the AND bit mask.

7. Because the image of a DIB is stored from bottom to top, flip the

   scanlines of the AND bit mask.

8. Create a cursor by calling the CreateCursor() function, specifying the

   AND and XOR bit masks.

To create a cursor from a bitmap DIB, use the following eight steps:

1. Obtain a handle to the DIB in the bitmap.

2. Call the GetSystemMetrics() function with the SM_CXCURSOR and

   SM_CYCURSOR indexes to determine the width and height of cursors

   supported by the installed video driver.

3. Change the size of the bitmap to match the size of the system's

   cursors.

4. If the bitmap is a color bitmap, convert it to monochrome. (All

   cursors are monochrome.)

5. Save the XOR mask bits in memory.

6. Create a monochrome bitmap for the AND bit mask. Fill it with any

   desired pattern.

7. Save the AND mask bits in memory.

8. Create a cursor by calling the CreateCursor() function, specifying the

   AND and XOR bit masks.

Creating Icons

--------------

In the GDIRSRCS sample, the functions that create icons are in the

ICON.C file.

The process to create an icon from a cursor or from another icon

resource file has eight steps. While the following discussion

describes the process of creating an icon based on a cursor, the

process to create an icon based on another icon is the same.

1. Obtain a pointer to the bits of the DIB in the cursor.

2. Divide the height of the DIB by two because the DIB contains both

   the AND and XOR bitmaps.

3. Calculate the offset to the AND mask bits.

4. Calculate the offset to the XOR mask bits.

5. Create a device dependent monochrome bitmap with the bits of the

   XOR mask.

6. Obtain the contents of the device dependent XOR bit mask and store

   it in memory. The AND bit mask is a monochrome bitmap. Because

   device independent and device dependent monochrome bitmaps share

   the same format, there is no need to convert the AND bit mask.

7. Because the image of a DIB is stored from bottom to top, flip the

   scanlines of the AND bit mask.

8. Create a cursor by calling the CreateCursor() function, and specifying

   the AND and XOR bit masks.

To create an icon from a bitmap DIB, use the following seven steps:

1. Obtain a handle to the DIB in the bitmap.

2. Call the GetSystemMetrics() function with the SM_CXICON and SM_CYICON

   indexes to determine the width and height of icons supported by the

   installed video driver.

3. Change the size of the bitmap to match the size of the system's

   icons.

4. Save the XOR mask bits in memory.

5. Create a monochrome bitmap for the AND bit mask. Fill it with any

   desired pattern.

6. Save the AND mask bits in memory.

7. Create an icon by calling the CreateIcon() function, and specifying

   the AND and XOR bit masks.

Additional reference words: 3.00 3.10 softlib GDIRSRCS.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiCurico


SAMPLE: Code Uses Keyboard Hook to Access Help

Article ID: Q83233

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

F1CDHELP is a file in the Microsoft Software Library that demonstrates how

an application can implement context sensitive help for the dialog boxes

provided by the dynamic-link library (DLL) COMMDLG.DLL (the common dialog

box DLL). When the user presses the F1 key, the application calls Windows

Help.

The recommended user interface for an application to provide access to

Windows Help is through the F1 key. This article describes a technique that

can be used with the common dialog box DLL to bring up context sensitive

help for each dialog box. The sample uses the SetWindowsHookEx() function

to set a task-specific keyboard hook, which monitors keyboard input and

responds to the F1 key.

Because this application uses a task-specific hook, the hook function code

resides in the application's .EXE file and is not required to be in a fixed

code page in a DLL. (The filter function for each system- wide hook must be

in a DLL.)

Download F1CDHELP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for F1CDHELP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download F1CDHELP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get F1CDHELP.EXE

MORE INFORMATION

================

The technique used in this article is straightforward and minimizes the

number of global variables required. The application installs the keyboard

hook and calls the RegisterWindowMessage() function to define a help

message. When an application registers the help message, the common dialog

box DLL notifies the application each time the user chooses the Help button

in one of the common dialog boxes. The DLL sends the help message to the

window procedure of the dialog box's parent window.

When the keyboard hook function detects that the F1 key is pressed, it

posts a WM_COMMAND message to the appropriate window procedure. In the

F1CDHELP example, the message is posted either to the main window (when no

dialog box is displayed) or to the dialog box's window procedure. If the

message is posted to one of the common dialog boxes, wParam is set to

pshHelp; the application simulates choosing the Help button in the common

dialog box. Otherwise, wParam is set to IDM_HELPCONTENTS; the application

simulates selecting a menu item in the application.

The following code demonstrates installing the hook and registering

the help message in response to a WM_CREATE message:

   case WM_CREATE:

      // Install the keyboard hook

      lpfnKbrdHook = MakeProcInstance((FARPROC)KeyboardHook, ghInst);

      ghKbrdHook = SetWindowsHookEx(WH_KEYBOARD, lpfnKbrdHook,

                                    ghInst, GetCurrentTask());

      // Register the help message. The common dialog box DLL sends this

      // message when the user chooses the Help file in a common

      // dialog box.

      gwHelpMsg = RegisterWindowMessage((LPSTR)HELPMSGSTRING);

      break;

The following code demonstrates removing the keyboard hook in response

to a WM_DESTROY message:

   case WM_DESTROY:

      UnhookWindowsHookEx(ghKbrdHook);

      break;

The hook function receives notification about the F1 key and posts a

message as appropriate:

DWORD FAR PASCAL KeyboardHook(int iCode, WPARAM wParam, LPARAM lParam)

{

   if (iCode < 0 || iCode != HC_ACTION)

      return CallNextHookEx(ghKbrdHook, iCode, wParam, lParam);

   if (wParam == VK_F1)

      // If this is a repeat or the key is being released, ignore it.

      if (lParam & 0x80000000 || lParam & 0x40000000)

         return CallNextHookEx(ghKbrdHook, iCode, wParam, lParam);

      else

      {

         if (IsWindowEnabled(ghWnd)) // F1 pressed in main window?

            PostMessage(ghWnd, WM_COMMAND, IDM_HELPCONTENTS, 0L);

         else                        // F1 pressed in a dialog box

            PostMessage(GetActiveWindow(), WM_COMMAND, pshHelp, 0L);

      }

   return CallNextHookEx(ghKbrdHook, iCode, wParam, lParam);

}

The second PostMessage() call above is executed when the user requests help

in a specific common dialog box. This simulates choosing the Help button in

the dialog box. Because the application registered the help message (during

the processing of its WM_CREATE message), the common dialog box DLL will

send the gwHelpMessage to the parent window procedure. An application can

process this message as follows:

   default:

      if (message == gwHelpMsg)  // Help requested in a common dialog

                                 // box

      {

      // The lParam points to an OPENFILENAME or a CHOOSECOLOR data

      // structure. The application can differentiate between them by

      // checking the structure's size, which is in the first four

      // bytes (a DWORD) of the structure. This allows the application

      // to display different help for each of the common dialog boxes.

      dwStructSize = (DWORD)(*(LPDWORD)lParam);

      switch (dwStructSize)

         {

         case sizeof(OPENFILENAME):

            MessageBox((HWND)wParam, "Help requested for OpenFile",

                       gszAppName, MB_OK);

            break;

         case sizeof(CHOOSECOLOR):

            MessageBox((HWND)wParam, "Help requested for ChooseColor"

                       gszAppName, MB_OK);

            break;

         default:

            break;

         }

      break;

      }

      else // Not a help message

         return DefWindowProc(hWnd, message, wParam, lParam);

Additional reference words: 3.10 softlib F1CDHELP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrHks


SAMPLE: Save and Restore Window Size, Position, Sample Code

Article ID: Q83234

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Many applications available today allow the user to store the size and

position of the application's main window in an initialization file. The

next time the user runs the application, the stored size and position

information is used to create the main window. The Windows File Manager and

Program Manager are examples of applications that save and restore size and

position information.

Under Windows 3.0, many operations are required to retrieve the normal size

and position for a window if it is maximized or minimized. Under Windows

3.1, the GetWindowPlacement() function has been provided to perform this

task. GetWindowPlacement() provides the size and position of a restored

window at all times, even when the window is minimized or maximized. The

SetWindowPlacement() function allows an application to change its restored

size and position at all times.

The GetWindowPlacement() function stores the following information

regarding a specified window into a WINDOWPLACEMENT structure:

 - Its current state (maximized, minimized or normal)

 - Its maximized position

 - Its minimized position

 - The rectangle that the window occupies in its normal position

The SetWindowPlacement() function restores a specified window to the state

described by a WINDOWPLACEMENT structure.

MDIREST is a file in the Microsoft Software Library that demonstrates using

GetWindowPlacement() to save the state of all windows in a multiple

document interface (MDI) application when the application shuts down. When

the user runs the application a second time, SetWindowPlacement() uses the

stored information to restore the state of the windows.

Download MDIREST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MDIREST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MDIREST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MDIREST.EXE

Additional reference words: 3.00 3.10 softlib MDIREST.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Unlocking Large-Model Extra Data Segments

Article ID: Q83363

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

An application that is compiled using the large memory model can have

multiple code segments and multiple data segments.

Under Windows 3.0, all the data segments except for the first one (the

so called "extra" data segments) are loaded into memory segments that

are fixed and page locked. Fixed and page locked segments interfere

with effective memory management. They reduce the amount of free

memory addressed below 1 megabyte (MB) in the linear address space,

and in some cases, cause out-of-memory errors as additional

applications are run.

Under Windows 3.1, extra data segments are loaded into movable memory

and the above difficulties with fixed and page locked segments do not

apply.

A large model application can change the attributes of its extra data

segments by calling the GlobalPageUnlock and GlobalUnfix functions.

However, to do this effectively, the application must be able to

enumerate the selectors for its extra data segments.

LARGEAPP is a file in the Microsoft Software Library that demonstrates

using the GlobalPageUnlock and GlobalUnfix functions to change the

attributes of an application's extra data segments. LARGEAPP contains

the source code to two applications: LARGEAPP, which is a large-model

application for the Windows environment, and SYMSEG, which is an

MS-DOS (non-Windows) application.

SYMSEG is a utility that reads a symbol file produced by the Microsoft

Linker, and creates a table of the data segments in an application.

LARGEAPP uses the information from this table to enumerate its own

data segments.

LARGEAPP determines the version of Windows under which it is running.

The segment attributes must be changed only if the application is

running under Windows 3.0.

Download LARGEAPP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LARGEAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LARGEAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LARGEAPP.EXE

Additional reference words: 3.00 3.10 softlib LARGEAPP.ZIP

KBCategory: kbprg kbfile

KBSubcategory: KrModls


SAMPLE: Code Demonstrates Flashing an Edit Control

Article ID: Q83364

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

If an application window or dialog box has a number of edit controls, the

user can lose track of the control that has the input focus. FLSHEDIT is a

file in the Microsoft Software Library that demonstrates how to make an

edit control flash to indicate that the control has the input focus. The

technique used by FLSHEDIT is similar to calling the FlashWindow function.

FlashWindow flashes the caption bar on a window to gain the user's

attention.

Download FLSHEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FLSHEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FLSHEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FLSHEDIT.EXE

MORE INFORMATION

================

The FLSHEDIT sample contains a dialog box with four edit controls. The

application uses one timer, which is used to flash whichever edit control

has the focus. The application sets the timer each time an edit control

receives the input focus (an EN_SETFOCUS message). The timer is destroyed

when an edit control loses the input focus (an EN_KILLFOCUS message) or

when the context of the edit control changes (an EN_CHANGE message).

When the specified time elapses and the application receives a WM_TIMER

message, the application invalidates the contents of the edit control and

specifies the new text and background colors. Then Windows redraws the

control using the new colors.

Therefore, a control stops flashing when either of the following events

take place:

 - The user takes the input focus away from the control.

 - The user changes the text contents of the control.

The FLSHEDIT application provides an option to stop the flashing and to

change the color of the flashing.

In addition to flashing, the FLSHEDIT sample changes the text in an edit

control to indicate that the control has the input focus. However, if the

user changes the contents of an edit control, the changed text remains even

after the user moves the input focus to another control. If the user

changes the text to an empty string, the edit control regains its default

contents.

Windows 3.0 does not properly change the background color of a single-line

edit control. For additional information on this problem, which has been

corrected in Windows 3.1, please see the following article(s) in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q67204

   TITLE     : FIX: Cannot Change Single-Line Edit Control Color

FLSHEDIT incorporates the first method provided by this Knowledge Base

article.

Additional reference words: 3.00 3.10 softlib FLSHEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


Sample Code Demonstrates Using Private Dialog-Box Class

Article ID: Q83365

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

PVTDLG is a file in the Microsoft Software Library that demonstrates using

a private dialog-box class in an application. The PVTDLG application

demonstrates using a private dialog-box class by itself and in

conjunction with another dialog box procedure. PVTDLG registers a

private dialog-box class that specifies a number of additional window

extra bytes. The sample stores the colors to paint each window in the

allocated space.

Download PVTDLG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PVTDLG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PVTDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PVTDLG.EXE

MORE INFORMATION

================

A private dialog-box class is a technique that allows one callback

procedure to process messages that are common to several different

dialog boxes. The private dialog-box class encapsulates code that

would otherwise be repeated in each dialog procedure.

When Windows has a message for a dialog box that is a member of a

private dialog-box class, it calls the private dialog-box class

procedure. After the private dialog-box class procedure completes its

processing, it must call the DefDlgProc function.

The next step depends on the contents of the lpDialogFunc parameter in

the application's call to the CreateDialog or DialogBox functions. If

lpDialogFunc is NULL, the DefDlgProc function performs its default

processing for the message and processing of that message is complete.

If lpDialogFunc is not NULL, DefDlgProc calls the specified procedure.

If the dialog box procedure returns FALSE, DefDlgProc performs its

default processing for the message. If the dialog box procedure

returns any other value, DefDlgProc skips the default processing and

returns.

Additional reference words: 3.00 3.10 softlib PVTDLG.ZIP

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Windows 3.1 Window Styles

Article ID: Q83556

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Microsoft Windows version 3.1 introduces five new window styles and

two new extended window styles. An application can specify any of the

five new window styles as the dwStyle parameter for the CreateWindow

function. Likewise, an application can specify either of the two new

extended window styles as the dwExStyle parameter for the

CreateWindowEx function.

STYLES is a file in the Microsoft Software Library that demonstrates using

all the styles listed below except for MDIS_ALLCHILDSTYLES.

Download STYLES.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for STYLES.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download STYLES.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get STYLES.EXE

MORE INFORMATION

================

The text below explains the behavior of windows created with the

window styles added to Windows 3.1.

Combo Box Style

---------------

CBS_DISABLENOSCROLL -- The list box portion of a combo box shows a

disabled vertical scroll bar when the list box can display all items

it contains without scrolling the contents. Without this style, the

scroll bar is hidden when the list box can display all items.

Edit Control Styles

-------------------

ES_READONLY -- The user cannot enter or edit text in the edit control.

ES_WANTRETURN -- This style can be used for a multiline edit control

in a dialog box. Each time the user presses the ENTER key while the

multiline edit control has the focus, Windows adds a carriage return

to the edit control's contents. Without this style, pressing the ENTER

key triggers the dialog box's default push button. This style does not

affect a single-line edit control.

List Box Style

--------------

LBS_DISABLENOSCROLL -- A list box shows a disabled vertical scroll bar

when the list box can display all items it contains. Without this

style, the scroll bar is hidden when the list box can display all

items.

MDI Client Style

----------------

MDIS_ALLCHILDSTYLES -- This style can be specified when an application

creates multiple document interface (MDI) client windows. When an

application creates MDI children of an MDI client window that has the

MDIS_ALLCHILDSTYLES style, Windows will create the children with

exactly the styles specified in the style field of the MDICREATESTRUCT

structure; the default MDI child window styles are not enforced.

The text below explains the behavior of windows created with the

extended window styles added to Windows 3.1.

WS_EX_ACCEPTFILES -- The window will accept files using the drag-drop

interface.

WS_EX_TOPMOST -- Windows places the window above all non-topmost

windows. The window will stay above all non-topmost windows even when

the window is deactivated. After a window is created, an application

can use the SetWindowPos function to add or remove this attribute.

Additional reference words: 3.10 softlib STYLE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Executing Excel Functions with Return Values Using DDE

Article ID: Q83661

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

In the Windows environment, an application cannot use the WM_DDE_EXECUTE

message to execute a Microsoft Excel function that returns a value. Excel

enforces this limitation because it has no mechanism to provide the return

value to the client application. If the client application is not

interested in the function's return value, it can work around this

limitation by posting a WM_DDE_EXECUTE message to Excel with commands to do

the following:

 - Create a macro sheet.

 - Write the desired function call to the macro sheet.

 - Run the macro.

DDEXL is a sample in the Microsoft Software Library that demonstrates this

technique. DDEXL allows the user to initiate a conversation with Excel,

execute a series of Excel commands, which draw a chart (using

CREATE.OBJECT), and terminate the conversation.

Download DDEXL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DDEXL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DDEXL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DDEXL.EXE

Additional reference words: 3.00 3.10 softlib DDEXL.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Creating a Shortcut-Key Edit Control

Article ID: Q83914

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

HOTKEYED is a file in the Microsoft Software Library that demonstrates how

to implement a shortcut-key edit control. A user can define a shortcut key

for an application. When the user presses the shortcut key, Windows

activates the corresponding application.

Download HOTKEYED.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HOTKEYED.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HOTKEYED.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HOTKEYED.EXE

MORE INFORMATION

================

HOTKEYED demonstrates how an application can implement a shortcut-key

(hot key) edit control. The application contains a dialog box in which

the user can specify which shortcut key the application will use. This

dialog box uses a subclassed edit control to display the name of the

shortcut key entered by the user. The edit control verifies that the

shortcut key is valid before displaying its name, and the control does

not permit the user to enter an invalid shortcut key. HOTKEYED calls

the GetKeyNameText function to retrieve the names of the specified

keys.

After the user enters a valid shortcut key, the application will

install the shortcut key. HOTKEYED installs a shortcut key by calling

the SetWindowsHookEx function to install a task-specific keyboard

hook. The application provides a menu selection to remove the shortcut

key. Closing the application also removes the shortcut key.

Once the shortcut key is installed, the application's window caption

flashes to inform the user that a shortcut key is active. The caption

continues to flash until the shortcut key is removed. When the user

presses the shortcut key, the background color of the main window

changes.

A shortcut key must use the ALT key and/or the CTRL key as a modifier.

The SHIFT key can also be specified as a modifier, but only in

combination with the ALT and/or CTRL keys. The ESC, ENTER, TAB, and

PRINT SCREEN keys and the SPACEBAR are not valid shortcut keys.

The user can erase a key combination from the shortcut key edit

control with the BACKSPACE key. Alternatively, the user can enter a

different shortcut key.

Additional reference words: 3.10 softlib HOTKEYED.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Adding and Removing Caption of a Window

Article ID: Q83915

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

NOTITLE is a file in the Microsoft Software Library that demonstrates

adding and removing the title (caption) of a window.

Download NOTITLE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S13405.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NOTITLE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NOTITLE.EXE

MORE INFORMATION

================

In the NOTITLE sample, when the window has a caption and the user selects

NoTitle from the main menu, the caption is removed. When the user double-

clicks the window without a caption by using the left mouse button, the

caption is added to the window.

NOTITLE removes the caption by performing the following five steps:

1. Removes the menu from the window by calling the SetMenu() function

   with NULL as the hMenu parameter.

2. Retrieves the current window style by calling GetWindowLong with

   GWL_STYLE as the nIndex parameter.

3. Removes the caption bit.

4. Calls SetWindowLong() with GWL_STYLE to change the style of the

   window.

5. Calls InvalidateRect() to instruct the application to redraw the

   window.

NOTITLE places the caption on the window by performing the following

five steps:

1. Adds the menu to the window by calling the SetMenu() function with the

   menu handle as the hMenu parameter.

2. Retrieves the current window style by calling GetWindowLong() with

   GWL_STYLE as the nIndex parameter.

3. Adds the caption bit.

4. Calls SetWindowLong() with GWL_STYLE to change the style of the

   window.

5. Calls InvalidateRect() to instruct the application to redraw the

   window.

Additional reference words: 3.00 3.10 softlib NOTITLE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Code Demonstrates How to Add Menus to a Dialog Box

Article ID: Q84129

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

DBMENU is a file in the Microsoft Software Library that demonstrates how to

add menus to a dialog box. Placing a menu on a dialog box is not part of

the Common User Access (CUA) standard, however, Windows does support it.

This article discusses some requirements that must be observed to use

a menu on a dialog box.

Download DBMENU.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DBMENU.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DBMENU.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DBMENU.EXE

MORE INFORMATION

================

To properly use a menu on a dialog box, an application must use certain

dialog box styles and avoid others. For the user to traverse a dialog box

menu using the LEFT and RIGHT ARROW keys, the dialog box must have both the

WS_CAPTION and WS_SYSMENU styles. The WS_SYSMENU style adds a system menu

to the dialog box. To enable the user to close the dialog box by choosing

Close from the system menu, process the WM_COMMAND message in the dialog

box procedure. If wParam is set to IDCANCEL, the user has closed the dialog

box in this manner.

The dialog box must not use the DS_MODALFRAME style because the menu is not

painted properly when this style is specified. If desired, use the

WS_BORDER style to place a thin black border around the dialog box. Do not

use the WS_CHILD style in any dialog box. Include the WS_VISIBLE style to

ensure that the dialog box is drawn on the screen.

Accelerator keys can be used only on modeless dialog boxes created by one

of the CreateDialog* functions. An application processes accelerator keys

by calling the TranslateAccelerator() function in its main message loop.

Modal dialog boxes have a "private" message loop and the application cannot

insert the necessary call to TranslateAccelerator().

An application can simulate a modal dialog box with a modeless dialog box

by calling EnableWindow() to disable the application's main window once the

dialog box is displayed. The application must call EnableWindow() to enable

the main window before destroying the modeless dialog box.

Do not use the following key combinations as accelerators: CTRL+H, CTRL+I,

and CTRL+M. For additional information, please see the following article(s)

in the Microsoft Knowledge Base:

   ARTICLE-ID: Q67293

   TITLE     : Some CTRL Accelerator Keys Conflict with Edit Controls

The following code demonstrates the additional function calls needed

in the main message loop for an application to process accelerator

keys on a modeless dialog box:

// Accelerators for the main window and dialog are in the same

// accelerator table

hAccel = LoadAccelerators(ghInstance, "ACCELTABLE");

while (GetMessage(&msg, NULL, NULL, NULL))

{

   // Determine the destination for this message

   hWndAccel = GetActiveWindow();

   if (!(hWndAccel

         && TranslateAccelerator(hWndAccel, hAccel, (LPMSG)&msg)))

   {

      // Note: If the dialog does not exist, ghModelessDlg is 0

      if (!(ghModelessDlg && IsDialogMessage(ghModelessDlg, &msg)))

      {

         TranslateMessage(&msg);

         DispatchMessage(&msg);

      }

   }

}

Additional reference words: 3.00 3.10 softlib DBMENU.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Undesirable Interactions Between Dialog Box Types

Article ID: Q84133

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

Some combinations of modal and modeless dialog boxes create undesirable

side effects due to their design and implementation. This article describes

the side effects and methods to avoid them. The following list of side

effects may not be complete, and will be updated as additional side effects

are discovered.

Side Effects

------------

1. Unable to change focus with the keyboard if a modeless dialog box

   is created as the child of an active modal dialog box.

2. Unable to change focus with the keyboard if a modeless dialog box

   is owned by an active modal dialog box.

3. Input focus moves to another application if a modeless dialog box

   is destroyed during processing of the WM_INITDIALOG message of a

   modal dialog box owned by the application's top-level window.

DLGS is a file in the Microsoft Software Library that demonstrates the

three side effects listed above, explains the causes of each, and

demonstrates the method listed below to avoid each problem.

Download DLGS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLGS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLGS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLGS.EXE

MORE INFORMATION

================

Sections A and B below list some characteristics of the design and

implementation of modal and modeless dialog boxes. Section C below explains

the causes of the side effects listed above and techniques to avoid these

side effects.

Section A: Characteristics of a Modal Dialog Box

------------------------------------------------

 - A modal dialog box has its own message loop to process messages from

   the application's queue without involving the application's message

   loop. This private message loop is active as long as the modal

   dialog is active.

 - A modal dialog box disables its owner to prevent the owner from

   processing input. By default, a modal dialog box disables only one

   window; the other windows remain enabled and can process user input

   unless they are explicitly disabled.

Section B: Characteristics of a Modeless Dialog Box

---------------------------------------------------

 - A modeless dialog box does not disable its owner window. Therefore,

   the user can continue to work with the owner window while the

   modeless dialog box is displayed.

 - A modeless dialog receives its messages through the application's

   main message loop.

 - An application typically calls the IsDialogMessage() function to

   process keyboard input for the modeless dialog box. IsDialogMessage()

   handles changing the focus between controls using the keyboard.

Section C: Explaining the Side Effects

--------------------------------------

Side Effect 1

-------------

Symptoms

When a modeless dialog box is created as a child of a modal dialog

box, the keyboard cannot be used to change the focus.

Cause

The modal dialog box's message loop does not provide the functionality of

the IsDialogMessage() function.

Resolution

Substitute a modeless dialog box for the modal dialog box. To make the

parent modeless dialog box appear modal, disable its owner window in the

code to process the WM_INITDIALOG message.

When a modal dialog box is in its message loop, all windows in the

application, including each modeless dialog box, receive its messages from

the modal dialog box's message loop. However, this message loop does not

provide the functionality of IsDialogMessage().

Side Effect 2

-------------

Symptoms

When a modeless dialog box is owned by a modal dialog box, the keyboard

cannot be used to change the focus.

Cause

The modal dialog box's message loop does not provide the functionality of

the IsDialogMessage() function.

Resolution

Substitute a modeless dialog box for the modal dialog box. To make the

parent modeless dialog box appear modal, disable its owner window in the

code to process the WM_INITDIALOG message.

Side Effect 3

-------------

Symptoms

If a modeless dialog box is destroyed during the processing of the

WM_INITDIALOG message for a modal dialog box owned by the application's top-

level window, the focus moves to another application.

Cause

No window is available to receive the focus.

Resolution

Substitute a modeless dialog box for the modal dialog box, as above.

Disable the owner window (to simulate modality) only after the modeless

dialog box is destroyed. Then Windows can put the input focus back to the

top window until the simulated modal dialog box is displayed.

Windows sends a WM_INITDIALOG message to a modal dialog box just before the

dialog is made visible. As part of destroying a window that has the input

focus, Windows removes the focus from the window and gives the focus to

another window. If the new modal dialog box destroys the modeless dialog

box as it processes a WM_INITDIALOG message, the modal dialog box is not

yet visible and cannot receive the input focus. Unless the application has

other visible windows, the only window that can receive the input focus is

the top-level window. However, because the top-level window owns the new

modal dialog box, it is disabled and cannot receive the input focus.

Because none of the active application's windows are eligible to receive

the input focus, Windows activates another application and gives the input

focus to one of its windows. When this other application receives the

focus, it moves to the front, over the application that created the modal

dialog box. As soon as the original application processes the WM_INITDIALOG

message, the modal dialog box is displayed and brought to the front.

The scenario above causes another application to be "sandwiched" between

the application's main window and the modal dialog box, which may confuse

the user. The following diagram illustrates the visual effect:

   +------------------------------------------------------------+

   |         Application 1's Main Window                        |

   |  +-------------------------------------------------------+ |

   |  |       Application 2's Main Window                     | |

   |  |       (on top of application 1's main window)         | |

   |  | +---------------------------------------------------+ | |

   |  | |      Application 1's Modal Dialog                 | | |

   |  | |      (on top of application 2)                    | | |

   |  | |                                                   | | |

   |  | +---------------------------------------------------+ | |

   |  +-------------------------------------------------------+ |

   +------------------------------------------------------------+

Additional reference words: 3.00 3.10 softlib DLGS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: TERMWAIT Spawns Task and Waits for its Termination

Article ID: Q84456

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

TERMWAIT is a file in the Microsoft Software Library that demonstrates how

an application can launch a child task and then wait for it to complete

before executing specific code. TERMWAIT uses notification messages from

the Toolhelp dynamic-link library (DLL) to determine that the child task

has completed. The techniques demonstrated by the TERMWAIT sample work for

both Windows and MS-DOS (non-Windows) child tasks.

Download TERMWAIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TERMWAIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TERMWAIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TERMWAIT.EXE

MORE INFORMATION

================

The TERMWAIT sample application calls the NotifyRegister() function to

install a notification callback function before it calls the WinExec()

function to launch the child task. If a callback function is

registered, it is called before any task in the system terminates. The

notification callback function calls the TaskFindHandle() function to

fill a TASKENTRY data structure with information about the terminating

task. When the callback determines that the child task has terminated,

it notifies the TERMWAIT application.

When it spawns the child task, TERMWAIT sets its bChildIsExecuting

global variable to TRUE. The notification callback resets this

variable to FALSE when the child task is complete. Any code that must

not execute while the child task is running can query the value of the

bChildIsExecuting flag. During the wait, any menu selections that

will cause reentrancy problems should be disabled. Doing so keeps the

user informed about the options that are presently valid. In the

TERMWAIT sample, the AfterChildHasTerminated() function contains code

that is executed only after the child task has completed.

If an application tracks a number of child tasks, its NotifyRegister()

callback function should process both the NFY_STARTTASK and

NFY_EXITTASK notifications. The callback function uses these

notifications to maintain a list of child task handles. Note that

while no two tasks will have the same handle, it is possible for task

handles to be reused. Consequently, if one task ends and a new task

begins, the new task can use the same task handle.

Version 3.1 of the Windows SDK is required to build the TERMWAIT

sample. However, the compiled code is compatible with both Windows 3.0

and 3.1. Note that because the TOOLHELP.DLL is not part of the default

installation for Windows 3.0, it must be installed into the Windows

system directory (by default, C:\WINDOWS\SYSTEM) before TERMWAIT will

run. The TOOLHELP.DLL file is provided as a redistributable file with

the Windows 3.1 SDK.

NOTE: The NotifyRegister callback function must be placed in a separate

source file and this file must be compiled with /GA/GEa. This is because

the NotifyRegisterCallback function is called with the Data Segment (DS) of

the task that installed the callback and the Stack egment of the task which

is notifying the callback. So SS != DS and /GA/GEs cannot be used to

compile this file.

Additional reference words: 3.00 3.10 synchronize softlib TERMWAIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: DLLSKEL Demonstrates DLL and Calling Application

Article ID: Q84932

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

DLLSKEL is a file in the Microsoft Software Library that contains the

source code for a minimal dynamic-link library (DLL) for the Windows

environment. DLLSKEL demonstrates how to correctly implement and

compile a multiple-segment DLL.

MORE INFORMATION

================

This sample has two parts: the multiple-segment DLL and an application

for the Windows environment. The application has all the features of

the Generic sample application provided with the Windows Software

Development Kit and a menu item that calls a function exported from

the DLL. The DLL function creates a message box when it is called by

the application.

The DLLSKEL sample demonstrates implicitly loading a DLL. However, the

modifications required to explicitly load the DLL are straightforward.

Download DLLSKEL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLLSKEL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLLSKEL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLLSKEL.EXE

To properly implement a DLL, one must consider several program

details. DLLSKEL demonstrates how to address all these details to

create a simple DLL.

In the DLLSKEL sample, the DLL has multiple code segments. The Windows exit

procedure (WEP) is placed in a fixed segment while the remainder of the

code is placed in movable, discardable segments. The WEP must reside in a

fixed code segment so that it can be called at all times, even when the

system has very little free memory. Consider the situation in which Windows

has discarded the segment containing the WEP. When Windows calls the WEP,

the segment must be loaded back into the system and all relocations to

other segments must be fixed up, which might require other segments to be

loaded. If the system does not have enough memory to load all the required

segments, or if some of the segments no longer exist, Windows will report

an unrecoverable application error (UAE) or general protection (GP) fault

because it cannot completely load the segment containing the WEP. If the

WEP is placed in a fixed code segment, the relocations are fixed up only

once, which completely avoids this situation.

The WEP was originally designed to allow a DLL that hooked an interrupt to

unhook it before termination, not to provide a general-purpose cleanup

procedure for a DLL. Under Windows 3.0, the WEP is called on a very small

stack located in the Windows Kernel, which will overflow if the WEP calls

Windows functions. There is enough room to unhook an interrupt, however.

Under Windows 3.1, the WEP is called on a 4K stack in the Windows Kernel,

which provides enough room to call Windows functions and to perform general

DLL cleanup. Because the WEP is called only once during the lifetime of a

DLL, it cannot be used to clean up each application instance that uses the

DLL. Under Windows versions 3.0 and 3.1, if a DLL requires each application

instance to call a cleanup routine, the DLL must explicitly provide the

routine, which each application instance must explicitly call.

An implicitly loaded DLL is loaded into memory before the calling

application is completely loaded. Therefore, the LibMain() function, which

is analogous to an application's WinMain() function, will be called before

the application's message queue is initialized. Therefore, the DLL must not

call functions that send messages to the application in LibMain().

Similarly, an implicitly loaded DLL is terminated after the calling

application has been removed from memory. Therefore, nothing in the WEP

must require the application to exist.

The LoadLibrary() function loads a DLL explicitly; the FreeLibrary()

function unloads a DLL. To modify DLLSKEL to explicitly load and free the

DLL:

1. Call the LoadLibrary() function to load the DLL. Save the library

   module handle.

2. Call the GetProcAddress() function, specifying the library module

   handle and the name of the function, to retrieve the pointer to the

   DLL function.

3. Call the FreeLibrary() function to free the DLL.

4. Modify the makefile to remove the call to IMPLIB and remove

   DLLSKEL.LIB from the linker command line.

Additional reference words: 3.10 3.00 softlib DLLSKEL.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: Code Simulates Changing List Box Style

Article ID: Q84978

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The windows styles specified when an application creates a list box are

fixed throughout its lifetime. LBCHANGE is a file in the Microsoft Software

Library that demonstrates using two list boxes to simulate changing the

style of a list box.

Download LBCHANGE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S13439.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LBCHANGE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LBCHANGE.EXE

MORE INFORMATION

================

When it creates a new window, Windows stores window style information in

several internal data structures. Windows refers to these data structures

when it performs window management tasks, including painting the window.

If an application calls the SetWindowLong() function to change the window

style dynamically, the new information is not reflected in the internal

data structures. For example, an application can't effectively change a

list box from the single selection style to the multiple selection style.

An application can work around this situation in two different ways:

 - Create two list boxes with different styles. The application shows

   the list box with the desired style and hides the other.

   -or-

 - Destroy the existing list box and create a new list box in its

   place.

The LBCHANGE sample demonstrates the first method, which is simple to

implement and runs efficiently. However, this method requires memory space

to store two copies of the list box contents.

Although the second method uses memory more efficiently, it requires more

work to implement. If the application changes the list box style often,

managing the contents of the list box by saving and reloading the contents

and tracking the selected items can become quite involved.

Additional reference words: 3.00 3.10 listbox softlib LBCHANGE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Code Demonstrates Superclassing MDI Client Window

Article ID: Q84979

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

An application can use superclassing to add new styles and functionality to

a multiple document interface (MDI) client window. SUPERMDI is a file in

the Microsoft Software Library that demonstrates superclassing an MDI

client window to change its behavior.

Download SUPERMDI.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S13440.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SUPERMDI.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SUPERMDI.EXE

MORE INFORMATION

================

Under a variety of circumstances an application might be designed to change

the predefined behavior of an MDI client window. Superclassing provides the

easiest and cleanest method to change window styles or to handle messages

in a unique manner.

By default, an MDI client window cannot accept mouse button double-clicks.

If an application superclasses the client window, the application can

change the window style of the client window and have it accept double-

clicks. An application can also use this method to change the MDI client

window background color.

The SUPERMDI sample application demonstrates changing the color of the MDI

client window and enabling the MDI client to respond to mouse button double-

clicks.

Additional reference words: 3.00 3.10 softlib SUPERMDI.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMdi


SAMPLE: Code Demonstrates Changing Dialog Box Size

Article ID: Q84980

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

The Color dialog box provided by the COMMDLG dynamic-link library (DLL)

expands to show additional controls when the user chooses the Define Custom

Colors button. The XPANDDLG sample application in the Microsoft Software

Library demonstrates how an application can implement similar behavior.

Download XPANDDLG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for XPANDDLG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download XPANDDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get XPANDDLG.EXE

The XPANDDLG sample implements changing the size of the dialog box through

the following three steps:

1. Create the dialog box at its large size.

2. Call the MoveWindow() function to size the window to the smaller size

   when the dialog box procedure receives a WM_INITDIALOG message.

3. To show the remainder of the dialog box on the screen, call

   MoveWindow() again.

Additional reference words: 3.00 3.10 softlib XPANDDLG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Code Demonstrates Keeping an Icon Fixed in Place

Article ID: Q84981

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

Some applications are designed to place an icon at a fixed location on the

screen where the icon must remain. One application of this type is the

FIXDICON sample in the Microsoft Software Library. When the user minimizes

the application, it draws an icon on the screen. If the user drags the icon

with the mouse, the icon "snaps back" to its specified position. If the

user chooses the Arrange Icons button in the Task Manager's Task List, the

icon appears momentarily at a new position assigned by Windows. Then it

returns to the position assigned by the application.

In the FIXDICON sample, the window procedure for the main window processes

the WM_MOVE message. If the window is represented as an icon, the

application calls the SetWindowPos function to position the icon at its

specified position.

Download FIXDICON.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FIXDICON.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FIXDICON.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FIXDICON.EXE

Additional reference words: 3.00 3.10 softlib FIXDICON.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiCurico


SAMPLE: Read-Only Edit Control Compatible with Windows 3.0

Article ID: Q85178

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

Windows version 3.1 introduces the ES_READONLY edit control style. When an

application creates a control and specifies the ES_READONLY style, the

control retains all the text display properties of an edit control while

preserving the content of the control from any modifications.

RROEDIT is a file in the Microsoft Software Library that demonstrates how

to create a read-only edit control using techniques that are compatible

with Windows versions 3.0 and 3.1. Using the techniques demonstrated by

RROEDIT, an application can switch an edit control to read-only mode and

back to normal behavior.

Download RROEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RROEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RROEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RROEDIT.EXE

The RROEDIT sample subclasses the edit control. In read-only mode, the

subclass procedure traps the WM_CHAR, WM_CUT, and WM_PASTE messages and

throws them away. All other messages are processed without any intervention

from the subclass procedure. The user can copy text from the edit control

at all times.

Additional reference words: 3.00 3.10 softlib RROEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Code Demonstrates Window Status Bar

Article ID: Q85203

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

An application can implement a status bar at the bottom of its main

window to provide information to the user. For example, Microsoft Word

for Windows and Microsoft Excel for Windows provide status bars. The

status bar in these applications presents the state of the CAPS LOCK

key, insert mode, extended selection mode, and so forth. STATBAR is a

file in the Microsoft Software Library that demonstrates how to create a

status bar for an application.

Download STATBAR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for STATBAR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download STATBAR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get STATBAR.EXE

MORE INFORMATION

================

The STATBAR application creates the status bar when its main window

receives a WM_CREATE message. Each time the main window receives a

WM_KEYUP message, the application determines whether the released key

is a "toggle key," such as the CAPS LOCK, NUM LOCK, or INS key. If so,

the application draws the status bar to reflect the current state of

the toggle key that changed state. When the status bar receives a

WM_PAINT message, the status bar repaints its entire client area.

Additional reference words: 3.00 3.10 softlib STATBAR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMdi


SAMPLE: Application Dynamically Links to a DLL Using a Class

Article ID: Q85282

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

The traditional methods an application uses to dynamically link to a

dynamic-link library (DLL) in the Windows environment, using the

LoadLibrary() and FreeLibrary() functions, can be awkward. The application

is required to call GetProcAddress() for each DLL function the application

links to, and the application is then required to store the returned

address in an array. The source code of the application must also contain a

prototype for each called function or the programmer must cast each

function parameter to the required type.

The object-oriented techniques of Microsoft C/C++ version 7.0 can be

applied to ease the process of dynamically linking with a DLL. An

application can define a class that links to the DLL and contains pointers

to each of the exported functions. Member functions of the class correspond

to the exported functions in the DLL.

DYNDLL is a file in the Microsoft Software Library that demonstrates using

a class, called CDynDLL, to dynamically link to a DLL. The CDynDLL

constructor loads the library and retrieves pointers to each function

exported by the DLL. The CDynDLL destructor frees the library. The member

functions of the CDynDLL class correspond to the functions exported by the

DLL.

Download DYNDLL.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DYNDLL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DYNDLL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DYNDLL.EXE

Additional reference words: 3.10 softlib DYNDLL.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrFileIO


SAMPLE: Application Shows Microsoft Foundation Classes

Article ID: Q85283

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

BLOCKS is a file in the Microsoft Software Library that demonstrates using

the Microsoft Foundation Classes (MFC). The user of the BLOCKS sample can

create rectangle, ellipse, and rounded rectangle graphical objects. Once

the objects are created, the mouse can be used to manipulate the objects by

changing their size or position on the screen. The user can save to a disk

file the state of objects in the BLOCKS window for use in another session.

Download BLOCKS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BLOCKS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BLOCKS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BLOCKS.EXE

The BLOCKS sample illustrates the structure of an MFC application. It

demonstrates the following:

 - Deriving a class from the CObject class

 - Using virtual functions with user-defined classes

 - Maintaining a list of classes

 - Creating static data and static member functions in a class

 - Using the serialization feature of the CObject class to save

   classes to and read classes from a disk file

BLOCKS demonstrates the following MFC classes: CArchive, CBrush,

CClientDC, CDC, CFile, CFrameWnd, CPaintDC, CPen, CPoint, CRect, and

CWinApp.

Additional reference words: 3.10 softlib BLOCKS.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Code Modifies the Font Common Dialog Box

Article ID: Q85431

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

MULTFONT is a file in the Microsoft Software Library that demonstrates how

an application can modify the ChooseFont() common dialog box to allow the

user to select more than one font simultaneously. The standard Font dialog

box only facilitates selecting one font; to choose more than one font, the

user must interact with the dialog box multiple times.

Download MULTFONT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MULTFONT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MULTFONT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MULTFONT.EXE

MORE INFORMATION

================

This article discusses techniques that are useful in applications that

allow the user to specify different fonts for different areas of the

application. MULTFONT displays information about an individual: name,

occupation, and social security number. For each line of information, the

user can use the Font dialog box to specify a different font for each line.

MULTFONT uses a custom dialog box template and a hook function in

conjunction with the Font dialog box. The template extends the Font dialog

box with a list box. The entries in the list box list the name of each data

element (name, occupation, and social security number). When the user

selects a font and chooses the Apply button, MULTFONT stores the font face

name, style, and point size in the list box. The text is stored outside the

list box's visible area.

For example, suppose the user selects the Name entry in the list box,

selects the Arial font, Bold style, size 10 points, and then chooses the

Apply button. The contents of the Name entry in the list box is updated as

follows:

       Select font for:

     -------------------

     |Name             | :Arial,Bold,10,

     |Occupation       | :Script,Normal,12,

     |SS_Number        | :Terminal,Normal,10,

     |                 |

     -------------------

An advantage of storing this information in the list box is that the

application can update the currently displayed font when the selection

changes. In the example above, if the user selects Occupation, the fields

of the Font dialog box should display the Script font. To obtain this

behavior, MULTFONT installs a hook function to process the LBN_SELCHANGE

message. When it receives an LBN_SELCHANGE message, MULTFONT performs the

following processing:

1. Parses the font information in the list box.

2. Simulates the corresponding selections of the Font, Font Style, and

   Size.

This processing updates the Font dialog box to display the font

associated with the currently selected field. For more information,

see the MAINWND.C file in the MULTFONT sample.

Additional reference words: 3.10 softlib MULTFONT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCmnDlg


SAMPLE: Application Splits a Window into Two Panes

Article ID: Q85633

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0and 3.1

----------------------------------------------------------------------

SUMMARY

=======

SPLITWIN is a file in the Microsoft Software Library that demonstrates

splitting a window into two panes using the mouse or keyboard. Each pane

can be scrolled independently in the vertical direction. Scrolling the

lower child horizontally, however, causes the upper child to scroll by the

same amount.

Download SPLITWIN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S13473.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SPLITWIN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SPLITWIN.EXE

MORE INFORMATION

================

The SPLITWIN sample creates a frame window that has a child window. The

child window fills the client area of the frame window. When the user

splits the window, SPLITWIN creates a second child window. The two child

windows are sized according to the position of the split bar.

The user can change the position of the split bar using either the mouse or

the arrow keys. After the window is split, it can be restored to its

original state by dragging the split bar off the frame window or by

selecting a position that does not provide enough room to create the second

window.

When the user clicks the mouse button in the split bar, SPLITWIN starts a

PeekMessage() loop that processes mouse and keyboard messages. The PatBlt()

function updates the position of the split bar as it is dragged.

Additional reference words: 3.00 3.10 synchronize softlib SPLITWIN.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Using the LZFILE Functions

Article ID: Q86267

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

LZFILE is a file in the Microsoft Software Library that demonstrates using

the functions provided by the LZEXPAND dynamic-link library (DLL).

LZEXPAND.DLL contains functions to decompress files compressed with

the COMPRESS.EXE application, which is an MS-DOS application that

implements the Lempel-Ziv data compression algorithm.

The LZFILE application demonstrates the following functions:

CopyLZFile, GetExpandedName, LZClose, LZCopy, LZDone, LZOpenFile,

LZRead, LZSeek, and LZStart. Each of the LZEXPAND functions work with

both compressed and uncompressed files under Microsoft Windows

versions 3.0 and 3.1.

Download LZFILE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LZFILE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LZFILE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LZFILE.EXE

MORE INFORMATION

================

LZFILE has three menu options to access files: Open, Copy 1, and Copy

Multiple. LZFILE uses the Open and Save As dialog boxes from the

common dialog box library to retrieve the filenames. If the user

chooses Open from the File menu, LZFILE calls LZOpenFile to open the

file and reads the contents with LZRead. If the file is compressed,

LZRead decompresses the file. LZFILE displays the file's contents in a

read-only edit control that fills the application's client area. The

LZClose function closes the file.

If the user selects Copy 1 from the File menu, LZFILE calls LZOpenFile

to open the source and destination files, calls LZCopy to copy the

source file into the destination file (which decompresses the source

if necessary), and calls LZClose to close both files.

If the user selects Copy Multiple from the File menu, LZFILE calls

LZStart to allocate memory for multiple file copies, LZOpenFile to

open the source and destination files, CopyLZFile to copy the files

(and decompress them if necessary), LZClose to close the files, and

LZDone to free the memory allocated by LZStart.

Additional reference words: 3.00 3.10 softlib LZFILE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrExt


SAMPLE: Using the Dynamic Data Exchange Management Library

Article ID: Q86926

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Windows operating system, dynamic data exchange (DDE)

is a form of interprocess communication that uses shared memory to

exchange data between applications. DDE is implemented by passing

messages between a client and a server application. The Dynamic Data

Exchange Management Library (DDEML), on the other hand, provides a set

of functions that simplify the task of adding DDE capability to an

application for the Windows environment.

Even though an application developed using the message-based DDE

protocol is fully compatible with those that use the DDEML, new

applications are strongly encouraged to use DDEML functionality.

The text below discusses the basics of a DDE transaction between a

client and a server engaged in an automatic (hot) link, and a code

sample that demonstrates the communication process.

BOUNCE is a sample application in the Software Library that shows two

balls bouncing from one application's window to another, graphically

demonstrating DDE using DDEML. The sample also illustrates how an

application can act as both client and server.

Download BOUNCE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BOUNCE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BOUNCE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BOUNCE.EXE

The BOUNCE file contains a directory structure. Use the "-d" option

when uncompressing to create a corresponding directory structure on

the destination drive. For example:

   bounce -d

MORE INFORMATION

================

An application that uses any of the DDEML functions must include the

DDEML.H header file in its source file, link with the DDEML.LIB

library, and ensure that DDEML.DLL is installed in a directory listed

in the MS-DOS PATH environment variable.

To use the DDEML, Windows must be running in protected mode; if not,

DDEML.DLL will not load. Although this is not a consideration for

applications running under Windows 3.1, it remains a concern for

applications running under Windows 3.0 and earlier. The -T switch for

the Resource Compiler (RC.EXE) marks an application so that the

Windows loader will load it only in protected mode. The -T switch is

used as follows:

   RC -T GENERIC.RES

An application developed with the DDEML can run in the Windows 3.0

environment. However, because the DDEML.DLL is not a standard part of

Windows 3.0, it must be included with the application and copied to

the system as part of the application installation process.

The following steps describe the requirements to use the DDEML in an

application:

 1. Define a callback function. In the same way the window manager

    sends "messages" along with wParam and lParam to an application's

    window procedure, DDEML sends "transactions" to the application's

    DDE callback function, to notify the application of DDE activity

    that takes place.

    This function, like any callback function in Windows, must be

    listed in the EXPORTS section of the application's module-

    definition (.DEF) file.

    The following is a sample structure for a server's DdeCallback

    function:

    HDDEDATA EXPENTRY DdeCallback(

        UINT type,      // transaction type

        UINT fmt,       // clipboard data format

        HCONV hConv,    // handle to the conversation

        HSZ hsz1,       // handle to a string

        HSZ hsz2,       // handle to a string

        HDDEDATA hData, // handle to global memory object

        DWORD dwData1,  // transaction-specific data

        DWORD dwData2)  // transaction-specific data

    {

     switch (wType)

        {

     case XTYP_DISCONNECT:

        ...

        return (HDDEDATA)NULL;

     case XTYP_CONNECT:               // hsz1 = Topic Name

                                      // hsz2 = Service name

        if ((!DdeCmpStringHandles(hsz1, hszTopicName)) &&

            (!DdeCmpStringHandles(hsz2, hszAppName)))

          return TRUE;   // SERVER supports Topic|Service

        else

          return FALSE;  // SERVER does not support Topic|Service

     case XTYP_CONNECT_CONFIRM:       // Follow-up transaction to

                                      // XTYP_CONNECT

        hConvServer = hConv;          // Save handle to conversation

        return (HDDEDATA)NULL;

     case XTYP_ADVSTART:        // Sent in response to CLIENT's

                                // request for an XTYP_ADVSTART

        if ((hConv == hConvServer)   // hConv = handle to conversation

                                     // hsz1  = topic name

            && (!DdeCmpStringHandles(hsz1, hszTopicName))

                                     // hsz2  = Item name

            && (!DdeCmpStringHandles(hsz2, hszFS_1)))

          return TRUE;   // SERVER supports this Topic|Service pair

        else

          return FALSE;  // SERVER does not support this pair

     case XTYP_ADVSTOP:  // Sent in response to CLIENT's request

                         // for an XTYP_ADVSTOP

        ...

        return (HDDEDATA)NULL;

     case XTYP_ADVREQ:

        // Sent when SERVER calls DdePostAdvise function to advise the

        // CLIENT of some data change.

        {

        if ((hConvServer == hConv)      // hConv = conversation handle

                                        // hsz1  = topic name

            && (!DdeCmpStringHandles(hsz1, hszTopicName))

                                        // hsz2  = Item name

            && (!DdeCmpStringHandles(hsz2, hszFS_1)))

          return DdeCreateDataHandle(..);

        return (HDDEDATA)NULL;

        }

     default:

        return (HDDEDATA)NULL;

        }

    }

 2. Before calling any DDEML function, an application must obtain an

    instance identifier for itself by calling the DdeInitialize

    function, as follows:

    DWORD idInst;

    FARPROC lpDdeProc;

    lpDdeProc = MakeProcInstance((FARPROC) DdeCallback, ghInstance);

    // Register application with the DDEML.

    if (DdeInitialize(&idInst,          // pointer to instance ID

              (PFNCALLBACK)lpDdeProc,   // points to Callback function

              APPCMD_FILTERINITS |

              CBF_FAIL_SELFCONNECTIONS |

              CBF_FAIL_EXECUTES,        // array of filter flags

              0L))

       return FALSE;

 3. DDEML functions often take handles to strings as parameters. The

    DdeCreateStringHandle function provides string handles, as

    illustrated below:

    HSZ hszAppName;

    hszAppName = DdeCreateStringHandle(idInst, "MyServer", NULL);

    if (hszAppName == 0)

       MessageBox(hWnd, "DdeCreateStringHandle failed.", "Oops!!",

                  MB_ICONEXCLAMATION | MB_OK);

    The DdeCmpStringHandles function compares string handles to each

    other, as shown below:

    case XTYP_CONNECT:               // hsz1 = Topic Name;

                                     // hsz2 = Service name

       if ((!DdeCmpStringHandles(hsz1, hszTopicName))

           && (!DdeCmpStringHandles(hsz2, hszAppName)))

         return TRUE;   // SERVER supports Topic|Service name pair

       else

         return FALSE;  // SERVER does not support Topic|Service

                        // name pair

 4. A DDEML server notifies all other DDEML applications in the system

    that a new server is available by calling the DdeNameService

    function to register its service name with the DDEML. A client

    application is not required to register.

    In the example below, note that the call to DdeNameService takes

    the hszAppName value obtained in step 3 above as its second

    parameter:

    // Register the SERVER's supported Service Name here.

    if (!DdeNameService(idInst,         // instance identifier

                        hszAppName,     // string specifying svc name

                        NULL,           // RESERVED

                        DNS_REGISTER))  // Name-service flags

      MessageBox(hWnd, "Unable to register SERVER", "Oops!!",

                 MB_ICONEXCLAMATION | MB_OK);

 5. A DDEML client initiates a conversation with the server by calling

    the DdeConnect function as follows. Server applications do not

    need to do this.

    HCONV hConvClient;

    // from DdeCreateStringHandle()

    HSZ hszSvrAppName, hszSvrTopicName;

    // Establish conversation with the SERVER

    hConvClient = DdeConnect(idInst,              // Instance ID

                             hszSvrAppName,       // Service Name

                             hszSvrTopicName,     // Topic Name

                             (LPVOID)NULL);

    If the value returned for hConvClient is NULL, the server is

    unable for a connection and no conversation is established. The

    DDEML signals the new conversation by sending an XTYP_CONNECT and

    an XTYP_CONNECT_CONFIRM transaction to the server's callback

    function.

 6. A DDEML client application established an automatic link with a

    server application by specifying XTYP_ADVSTART in a call to the

    DdeClientTransaction function. Server applications need not do

    this.

    In an automatic link, the server sends a data handle to the client

    application whenever the value of the specified data item changes.

    Conversely, a manual (warm) link causes the server to notify the

    client that the data has changed, but does not send the updated

    data value to the client. A client can specify a manual link by

    specifying XTYP_ADVSTART | XTYPF_NODATA in the call to

    DdeClientTransaction.

    if (!DdeClientTransaction(NULL, // pointer to server's data

                     0,             // data length

                     hConvClient,   // conversation handle

                     hszFS_1,       // item name

                     CF_TEXT,       // clipboard format

                     XTYP_ADVSTART, // start an ADVISE loop

                     1000,          // time-out in one second

                     NULL))         // points to result flags

       MessageBox(hWnd, szBuffer, "Oops!!",

                  MB_ICONEXCLAMATION | MB_OK);

    DDEML sends the XTYP_ADVSTART transaction to the server's callback

    function.

 7. Whenever the value of the data item changes, the server

    application calls the DdePostAdvise function to notify the client

    application, as follows. Client applications need not do this.

      DdePostAdvise(idInst, hszTopicName, hszFS_1);

    The DdePostAdvise function causes the DDEML to send an XTYP_ADVREQ

    transaction to the server application's callback function. The

    server processes the XTYP_ADVREQ transaction by returning a handle

    to the changed data. DDEML then notifies the client of the changed

    data by sending an XTYP_ADVDATA transaction to the client

    application's callback function with hData set to the data handle

    returned from the server application.

    When the server processes an XTYP_ADVREQ transaction, it calls

    DdeCreateDataHandle to create a data handle that contains the

    changed data item and returns this handle. If the server specified

    the HDATA_APPOWNED flag in the afCmd parameter of the

    DdeCreateDataHandle function, it must call the DdeFreeDataHandle

    function to free the shared memory associated with the handle.

    Otherwise, the data handle is owned by the system and the handle

    is invalidated after it is returned from the server's callback

    function.

    When the client processes an XTYP_ADVDATA transaction, it may take

    either of two courses of action: call the DdeGetData function to

    copy the data item from the global memory object to a local buffer

    and return the DDE_FACK value; or call the DdeAccessData function

    to obtain a pointer to the data object received from the server

    application, and then call the DdeUnaccessData function to release

    the pointer.

 8. A DDEML client application ends an advise loop (an automatic link)

    by specifying XTYP_ADVSTOP in a call to the DdeClientTransaction

    function, as in step 6, above. Server applications need not do

    this.

    if (!DdeClientTransaction(NULL,  // pointer to data passed to

                                     // server

                       0,            // data length

                       hConvClient,  // conversation handle

                       hszFS_1,      // item name

                       CF_TEXT,      // clipboard format

                       XTYP_ADVSTOP, // end an ADVISE loop

                       1000,         // time-out in one second

                       NULL))        // points to result flags

       MessageBox(hWnd, "Failed XTYP_ADVSTOP", "Oops!!",

                  MB_ICONEXCLAMATION | MB_OK);

    DDEML then sends the XTYP_ADVSTOP transaction to the server

    application's callback function.

 9. Either the client or the server application can call DdeDisconnect

    to terminate a conversation any time. Terminating a conversation

    invalidates the conversation handle specified by the hConv

    parameter.

    if (!DdeDisconnect(hConvClient))

       MessageBox(hWnd, "Unable to disconnect hConvClient", "Oops!!",

                  MB_ICONEXCLAMATION | MB_OK);

    DDEML sends the XTYP_DISCONNECT transaction to the partner in the

    conversation.

10. A server should call DdeNameService to unregister its service name

    just before terminating, as follows. A client application need not

    do this.

    // Unregister application's service Name with the DDEML.

    if (!DdeNameService(idInst,          // instance identifier

                        hszAppName,      // string specifying svc name

                        NULL,            // RESERVED

                        DNS_UNREGISTER)) // Name-service flags

      MessageBox(hWnd, "Unable to UNREGISTER Server.", "Oops!!",

                 MB_ICONEXCLAMATION | MB_OK);

11. After the application has finished using any string handles

    created by the DdeCreateStringHandle function, the handles must be

    freed, as follows:

    if (!DdeFreeStringHandle (idInst, hszAppName))

      MessageBox(hWnd, "DdeFreeStringHandle failed.", "Oops!!",

                 MB_ICONEXCLAMATION | MB_OK);

12. Each application should call DdeUnitialize to free the DDEML

    resources that the system allocated for the application, as

    follows:

    if (!DdeUninitialize(idInst))

      MessageBox(hWnd, "Unable to uninitialize.", "Oops!!",

                 MB_ICONEXCLAMATION | MB_OK);

13. When ever a DDEML function fails, it is a good practice to call

    the DdeGetLastError function to retrieve an indication of the

    failure. For a list of error codes and their possible causes,

    search for the following words in the Microsoft Knowledge Base:

       ddeml and error

Additional reference words: 3.00 3.10 softlib BOUNCE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Creating a Glossary Button in Windows Help

Article ID: Q87343

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

HLPGLOSS is a file in the Microsoft Software Library that demonstrates how

to add a Glossary button to the button bar in the Microsoft Windows Help

application. The help file for the Windows Program Manager is an example of

a popular help file that has a Glossary button. When the user chooses the

Glossary button, Help displays the Glossary topic in a secondary window.

Download HLPGLOSS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HLPGLOSS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HLPGLOSS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HLPGLOSS.EXE

MORE INFORMATION

================

To create a Glossary button, two items must be added to the Help

project (.HPJ) file:

1. In the [CONFIG] section, add the CreateButton macro, which creates

   the "Glossary" button and programs the button to jump to the topic

   that contains glossary information.

   The third parameter of the CreateButton macro can contain the

   JumpContents, JumpContext, or JumpID macro. Specify JumpContents to

   move to the Contents topic of a Help file. Specify JumpContext to

   jump to the topic in a Help file with a specific context number.

   Specify JumpID to jump to the topic in a Help file with a specific

   context identifier. Any of these macros can move to a topic in the

   current Help file or to a topic in a different Help file.

   NOTE: If the glossary topic is in a different .HLP file, the

   [WINDOWS] section in its .HPJ file must define the secondary

   window. For more information on the CreateButton macro, see pages

   309 and 310 of the "Programmer's Reference, Volume 4: Resources"

   manual distributed with version 3.1 of the Microsoft Windows

   Software Development Kit (SDK).

2. In the [WINDOWS] section, add a definition for the secondary window

   in which glossary information is displayed. This line defines the

   size, position, and color of the secondary window. For more

   information on the [WINDOWS] section of the .HPJ file, see pages 64

   through 66 of the Windows SDK "Programming Tools" manual.

The following fragment of an .HPJ file demonstrates these two steps:

[CONFIG]

; Because the help topic is in this Help file and the context

; identifier is available, the code below specifies the JumpId (JI)

; macro. The glossary is shown in the secondary "Glossary" window

; specified in the [WINDOWS] section below. The peculiar single quotes

; are significant. Note: In an actual Help project file, the following

; information appears on one line (no break).

CreateButton("Glossary_Btn","&Glossary","JI(`hlpgloss.hlp>Gloss',

`Glossary_Context')")

[WINDOWS]

; Define the secondary window for the glossary in the [WINDOWS]

; section of the HPJ file for the Help file that contains the glossary

; topic.

Gloss = "Glossary",(100,100,350,350),0,(255,255,255),(255,255,255)

Additional reference words: 3.10 3.00 WinHelp softlib HLPGLOSS.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsHlp


SAMPLE: Passing Ink Between Hedit Controls

Article ID: Q90485

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

To pass ink between hedit controls, an application must capture the ink

when the hedit control's parent window receives the HN_ENDREC notification

message. Then the application does either of the following:

 - Sends a WM_HEDITCTL message with wParam set to HE_SETINKMODE to begin

   collecting ink, and sends a WM_HEDITCTL message with wParam set to

   HE_STOPINKMODE to stop collecting ink.

 - Specifies RCO_SAVEHPENDATA in the lRcOptions field of the RC data

   structure.

INK2H is a file in the Microsoft Software Library that demonstrates

capturing ink and using the WM_HEDITCTL message.

Download INK2H.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for INK2H.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download INK2H.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get INK2H.EXE

MORE INFORMATION

================

The recognizer returns ink in the hpendata field of the RCRESULT structure.

Passing ink between hedit controls is more difficult than using a normal

device context (DC). Perform the following four steps to save the ink:

1. Perform either of the following:

   a. Specify RCO_SAVEHPENDATA in the lRcOptions field of the RC data

      structure.

   b. Send the WM_HEDITCTL message to the hedit control with HE_SETINKMODE

      in wParam to begin collecting ink. Send the WM_HEDITCTL message to

      the hedit control with HE_STOPINKMODE to stop collecting ink.

2. When the application receives an HN_ENDREC notification for the source

   hedit control, retrieve the handle to the memory containing the ink.

   (When recognition is complete, the recognizer sends a WM_COMMAND message

   with the HN_ENDREC notification as the high-order word of lParam and the

   ID of the hedit control in wParam.)

3. Use the SendMessage function to send a WM_HEDITCTL message with

   HE_GETINKHANDLE as the value for wParam. If the call is successful, the

   low-order word of the returned value contains a handle to the memory

   containing the ink.

4. Depending on the choice made at step 1 above, perform the corresponding

   step:

   a. If the RCO_SAVEHPENDATA flag was set in step 1, Windows will not

      delete the data after all corresponding WM_RCRESULT messages have

      been sent. Therefore, call the DestroyPenData function to delete the

      pen data when an HN_RCRESULT notification is received.

   b. If HE_SETINKMODE is used, call the DuplicatePenData function to save

      the ink into a block of memory allocated by the GlobalAlloc function.

The procedure to place the collected ink into another hedit control is very

similar. Send a WM_HEDITCTL message with wParam set to HE_SETINKMODE and

the low-order of lParam set to the handle to the memory block containing

the ink. Then send a WM_HEDITCTL message with wParam set to HE_STOPINKMODE.

The INK2H sample application demonstrates copying ink between hedit

controls using the HE_SETINKMODE and HE_STOPINKMODE values with a

WM_HEDITCTL message.

Additional reference words: 1.00 softlib INK2H.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenInk


SAMPLE: Annotating a Text File with Ink

Article ID: Q90486

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

An advantage for pen computers would be the ability to add handwriting to a

text file. This process is known as annotation. An application that

implements full-scale annotation must address several issues, including

movement, saving ink to a file, delayed recognition, and using gestures.

One of the most basic issues is movement.

ANNOTATE is a file in the Software Library that demonstrates one

scrolling algorithm that scrolls the ink and the text file appropriately.

Download ANNOTATE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ANNOTATE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ANNOTATE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ANNOTATE.EXE

MORE INFORMATION

================

For an application to attach ink to a specified position of a text file, it

must scroll and repaint the ink in the appropriate position as the text

moves. The ANNOTATE sample application demonstrates one of many possible

scrolling algorithms. ANNOTATE also demonstrates dynamically changing ink

color and width.

ANNOTATE calls the RedisplayPenData function to redisplay the ink and the

DuplicatePenData function to save ink over the life of the application.

ANNOTATE can serve as a foundation for other pen-centric annotation

applications.

Additional reference words: 1.00 softlib ANNOTATE.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenInk


SAMPLE: DYNBEDIT Changes From Edit to Bedit Control @ Run Time

Article ID: Q90839

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

PENWIN.DLL by default changes an edit control to an hedit control at run

time. However, the Pen Windows system does not have a built-in mechanism to

change an edit control to a bedit control at run time.

DYNBEDIT demonstrates how to change a normal edit control to a bedit

control at run time. This allows an application to run unmodified in either

Pen Windows or retail Windows.

Download DYNBEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DYNBEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DYNBEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DYNBEDIT.EXE

MORE INFORMATION

================

The basic steps to perform this transition are to query the information

from the edit control, destroy the edit control, and then call

CreateWindow() to make the new bedit control. However, there is a problem

with this procedure when using a font other than the system default font in

a dialog box. If a font statement is given (for example: FONT 8,"Helv"),

the combs of the bedit control will appear below the bottom border of the

control. This problem occurs because the Pen system bases the size of the

combs on the system font only rather than on the font specified. To work

around this problem, the application must modify the GUIDE structure in the

RC structure for the new control. By reducing the size of the GUIDE

structure, the Pen system will pick a new font, which matches the new GUIDE

size.

To accomplish this, the following steps need to be performed at either

WM_INITDIALOG or WM_CREATE depending upon the location of the edit control:

 1. Check to see if Pen Windows is running. If so, proceed to step 2.

 2. Get the handle to the edit control, the text in the edit control, and

    three different sets of dimensions:

    a. The location of the dialog box in screen coordinates.

    b. The location of the edit control in screen coordinates.

    c. The size of the edit control in pixels.

    The first two measurements can be accomplished with the

    GetWindowRect() function, and the third measurement can be

    accomplished with the GetClientRect() function.

 3. Destroy the original edit control.

 4. Create the new bedit control with a call to CreateWindow(). Use the

    following equations to calculate the values of x, y, dx, and dy:

       // EditRect is the location of the edit control in screen

       // coordinates.

       // DlgRect is the location of the dialog box in screen coordinates.

       // rect is the size of the edit control in pixels.

       x  = (EditRect.left - DlgRect.left)

       y  = (EditRect.top - DlgRect.top)

       dx = (rect.right - rect.left)

       dy = (rect.bottom - rect.top)

    You should also use the same ID number in the call to CreateWindow() as

    used by the original edit control.

 5. Send a WM_HEDITCTL message to the new bedit control with the wParam set

    to HE_GETRC to retrieve the RC structure. This will allow the

    application to modify the GUIDE structure.

 6. Calculate the new cyBox value. cyBox is the height of one cell in the

    bedit control. For example:

       // New cyBox value (height of one box).

       NewcyBox = (rect.bottom - rect.top);

 7. Calculate the new cxBox value by using a ratio between the old cyBox

    and the new cyBox. cxBox is the width of one cell in the control. For

    example:

       // Calculate new cxBox value by changing window ratio.

       rc.guide.cxBox = NewcyBox * rc.guide.cxBox / rc.guide.cyBox;

 8. Calculate the new cyBase value. cyBase is the distance from the top of

    the cell to the baseline of the comb. Again, use a ratio based upon the

    change between the old cyBox and the new cyBox. For example:

       // Calculate the new cyBase (distance from top of box to baseline).

       rc.guide.cyBase = NewcyBox * rc.guide.cyBase / rc.guide.cyBox;

 9. Calculate the number of cells that can now fit inside of the control.

    This is done by taking the width of the control, and dividing it by the

    width of a single cell. For example:

       // Calculate the number of cells that can fit in the bedit control.

       rc.guide.cHorzBox = (rect.right - rect.left) / rc.guide.cxBox;

10. Complete any additional changes needed for the control, and then

    replace the RC structure with the new one by sending a WM_HEDITCTL

    message with the wParam set to HE_SETRC. For example:

       // Replace the RC structure.

       SendMessage (hBEdit, WM_HEDITCTL, HE_SETRC, (long)(LPRC) &rc);

At this point, the Pen system will generate the correct font to fit inside

of the new GUIDE dimensions.

If the application chooses to send a WM_SETFONT message to the control, the

application then assumes responsibility for choosing a font that will fit

inside of the comb. The Pen system won't do any font picking if the

application uses the WM_SETFONT message. Using a WM_SETFONT message is

necessary if the application requires the use of any special font

characteristics (for example, italic).

The DYNBEDIT sample has been written to demonstrate the above process.

The code that makes the transition is located in ABOUT.C in the

WM_INITDIALOG case of PenDlgProc().

Additional reference words: 3.10 softlib DYNBEDIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Handling Callbacks with C++ Member Functions

Article ID: Q92433

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

The CALLB application demonstrates how to handle callbacks with C++

member functions. It is a companion application for the technical

article on the MSDN, "Calling All Members: Member Functions as

Callbacks."

Microsoft Windows version 3.1 has over 30 callback functions

that applications can use to enumerate objects, hook into the

hardware, and perform a variety of other activities. The article

explains why normal member functions cannot be used as callback

functions and gives several techniques for handling callbacks. The

article and source code are targeted toward Microsoft C/C++ version

7.0, but the ideas presented apply to all C++ compilers, including

those by Borland and Zortech.

CALLB contains eight makefiles that create six executables: MAKE1

creates CPROG1; MAKE2 generates a compile-time error and does not

create an executable; MAKE3, MAKE4, MAKE5, and MAKE6 create CPROG3,

CPROG4, CPROG5, and CPROG6, respectively; and TMAKE creates CTIMER.

Please refer to "Calling All Members: Member Functions as Callbacks"

for more information.

NOTE: Running CPROG1 generates a general protection (GP) fault by

design.

CALLB was built and tested under Microsoft Windows version 3.1.

Download CALLB.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for CALLB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CALLB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CALLB.EXE

Additional reference words: 3.10 EnumObjects EnumObjectsProc softlib

CALLB.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsMisc


SAMPLE: Demonstration of Using _fmalloc

Article ID: Q92436

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Smart Alloc (SMART) allows programmers to experiment using the _fmalloc()

function in the Microsoft Windows operating system. It is a companion

program for the technical article in the MSDN "Allocating Memory the Old

Fashioned Way: malloc and Windows Applications."

With Smart Alloc and Heap Walker, programmers can interactively explore the

behavior of _fmalloc(), _ffree(), GlobalAlloc(), GlobalFree(), and

_heapmin(). They can allocate memory either using GlobalAlloc() or

_fmalloc(), or from a DLL. They can determine when and how memory is

allocated easily, without recompiling.

The source code for Smart Alloc also demonstrates some interesting

features. Smart Alloc is a multiple-instance, large-model application when

compiled with Microsoft C/C++ version 7.0. Another interesting feature of

Smart Alloc is that it includes a dynamic link library (DLL) that

intercepts all calls SMART.EXE makes to GlobalAlloc(), GlobalReAlloc(), and

GlobalFree().

Smart Alloc was built with Microsoft C/C++ version 7.0 and tested under

Microsoft Windows version 3.1.

Download SMART.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SMART.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SMART.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SMART.EXE

Additional reference words: 3.10 malloc free large model GMEM_SHARE softlib

SMART.EXE

GMEM_DDESHARE GlobalAllocPtr GlobalFreePtr

KBCategory: kbprg kbfile

KBSubcategory: KrMm


SAMPLE: VERSTAMP Accesses the File Version Information Resouce

Article ID: Q92441

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SD) for Windows

   version 3.1

----------------------------------------------------------------------

VERSTAMP demonstrates how to use the VER.DLL and VER.LIB libraries,

which provide version-stamping for Microsoft(R) Windows(TM) and

MS-DOS(R) executable files.

To select an executable, a dynamic-link library (DLL), or a driver

file source and display its file version information in the main

window, choose the Open command from the File menu. If the file does

not have a version information resource, VERSTAMP notifies you with a

message box. If the file has a version information resource, choose

the More Info button in the main window to display the information. If

you choose the Install File button, VERSTAMP uses the VerFindFile()

function to determine where the source file should be installed. If

VerFindFile() returns an error, VERSTAMP displays a message box

prompting you to continue or abort. If you choose to continue,

VERSTAMP proceeds with the installation, captures the result of

VerInstallFile(), and displays it in a message box.

Download VERSTAMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for VERSTAMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download VERSTAMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get VERSTAMP.EXE

Additional reference words: 3.10 Softlib VERSTAMP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrExt


SAMPLE: Using Microsoft C Compiler Options with Windows

Article ID: Q92443

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Zusammen, which means "together" in German, is an application that scrolls

two different windows simultaneously. The user selects the windows by

clicking on the Windows1! and Windows2! menu and clicking on the

corresponding windows. To scroll both windows, the user clicks Zusammen's

scroll bars. This makes it easy to compare data in two different windows or

applications.

Zusammen consists of a program generated by MAKEAPP (see the MAKEAPP

abstract on the MSDN) and a dynamic-link library (DLL) called Picker that

selects the windows to be scrolled.

For more information on ZUSAMMEN, see the "Microsoft Windows and the C

Compiler Options" technical article on the MSDN.

ZUSAMMEN was built and tested under Microsoft Windows version 3.1.

Download ZUSAMMEN.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ZUSAMMEN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ZUSAMMEN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ZUSAMMEN.EXE

Additional reference words: 3.10 softlib zUSAMMEN.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrPnt


SAMPLE: Windows Application Produces Stack Trace

Article ID: Q92537

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

STKTRACE is a sample Windows-based application that contains the complete

code to obtain a stack trace of the "current task." The stack trace

includes symbolic information extracted from the symbol files, similar to

that produced by the Windows debug kernel at the time of a FatalExit. In

this sample, the stack trace is logged into a buffer and output to a

message box.

The STKTRACE sample uses the tool helper library and can be used in the

Windows versions 3.0 and 3.1 environments because TOOLHELP.DLL is a

redistributable.

Download STKTRACE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for STKTRACE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download STKTRACE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get STKTRACE.EXE

MORE INFORMATION

================

Usually, the Windows debug kernel produces a stack trace on the debug

terminal when the SPACE BAR or ENTER key is pressed at the time of a

FatalExit. For more information on stack traces produced by the debug

kernel, query on the following words in the Microsoft Knowledge Base:

   stack trace space bar

However, when you are writing a debugger or a large complex application, it

might be necessary to produce stack traces in your application. Then, the

STKTRACE sample code can be helpful.

This sample consists of two main modules, GETTRACE.C and GETSYMBOL.C, and a

driver module, STKTRACE.C, which merely calls the API from the GETTRACE.C

module. The GETTRACE.C module contains code to walk the stack of the

current task by using the tool helper library and the GETSYMBOL.C module

contains code to obtain symbol names from corresponding symbol (.SYM) files

by using the symbol file format. These two modules can be plugged into any

application or a DLL (dynamic-link library).

Note that the THSAMPLE application in the \SDK31\SAMPLES\TOOLHELP directory

also illustrates how to produce stack traces for a given task that is not

the current task. In contrast, the STKTRACE sample walks the stack of the

current task by obtaining the register values from the stack and using the

StackTraceCSIPFirst() and StackTraceNext() APIs from the tool helper

library. Also, the STKTRACE sample provides symbolic information in the

stack trace.

The GETSYM.C module provides symbolic information by using the symbol file

format documented in the Microsoft Windows SDK version 3.1 "Programmer's

Reference, Volume 4: Resources" manual. Given a segment:offset address,

this module finds the "nearest" public symbol in the corresponding symbol

(.SYM) file.

Additional reference words: 3.00 3.10 softlib STKTRACE.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: Corrections to the Windows 3.1 SDK Sample FONTEST

Article ID: Q92538

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The FONTEST sample program in the Microsoft Software Library contains some

corrections to problems that are in the version of the sample that shipped

with the Windows 3.1 SDK.

MORE INFORMATION

================

In the original version of the sample, some of the values entered in the

Set LogFont dialog box are mapped incorrectly to the underlying LOGFONT

structure. The value entered for Italic is mapped into the LOGFONT's

lfUnderline field and the value entered for Underline is mapped into the

LOGFONT's lfItalic field. This causes an italic font to be created when an

underline font is specified and an underline font to be created when an

italic font is specified. The version of FONTEST in the Software Library

corrects this problem.

When printing in the original version, if you choose a font from the Choose

Font common dialog box, the output will be in a smaller size font than the

output of the same font from another Windows-based application such as

Microsoft Write.

The common dialog box function ChooseFont() always returns the height of

the font in the lfHeight field of the LOGFONT structure based on the

vertical dpi (dots per inch) of the screen. When creating a font to send to

the printer, it is necessary to adjust the lfHeight field of the LOGFONT

using the vertical dpi of the printer. To adjust the height, use the

formula:

   Height = -(dpiY*point_size/72); //dpiY is dots per inch in Y direction

For an explanation of the above calculation, please see the following

articles in the Microsoft Knowledge Base:

   ARTICLE-ID: Q32677

   TITLE     : Font Metrics and the Use of Negative lfHeight

   -or-

   ARTICLE-ID: Q74000

   TITLE     : Calculating the Point Size of a Font

The FONTEST macro PT_TO_PIXELS in fontest.c performs the calculation to

adjust the height of the LOGFONT. This adjusted height is passed into the

FONTEST function PaintMetrics(), which creates a font and performs output.

However, in the original version of FONTEST, the value for the adjusted

height is not used. Because the dpi of most printers is greater than the

dpi of the screen, the font that is created is smaller than it should be.

The version of FONTEST in the Software Library uses the adjusted height

value when creating the font.

This sample uses the Windows 3.1 common dialogs, so you must have the

Windows 3.1 SDK to compile it.

Download FONTEST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FONTEST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FONTEST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FONTEST.EXE

Additional reference words: 3.10 softlib FONTEST.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiFnt


SAMPLE: Maintaining a Hidden Application

Article ID: Q92828

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

SUMMARY

=======

HIDAPP is a sample DLL (dynamic-link library) that uses a hidden

application to do file I/O for the DLL. Using this architecture, it is

possible for multiple applications to link to the DLL and access the file

through the DLL.

Download HIDAPP.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for HIDAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HIDAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HIDAPP.EXE

MORE INFORMATION

================

It is often desirable to have a DLL open and manage a data file. This way,

many applications can link to the DLL and access the file. Because all

access is done through the DLL, there are no problems associated with

having more than one application opening the file at the same time.

Under Windows, DLLs cannot own files; only applications can. File handles

are indices into the file table, which is stored in the task database. When

a DLL opens a file, the application that called the DLL owns that file

handle. If a DLL saves the file handle in a global variable and then later

tries to use it when it is called by a different application, then that

file handle will be invalid.

This HIDAPP sample application discusses one way to work around this

limitation. It consists of a DLL that uses a hidden application to access

files for the DLL that act as a server. When the first instance of client

application links to the DLL, the hidden application is executed and a data

file is opened. The handle for this data file is owned by the hidden

application. After this, other client applications may link to the DLL and

call functions to add and retrieve records from the data file. When the

last client application shuts down, the DLL closes the data file and shuts

down the hidden application.

Additional reference words: 3.00 3.10 softlib HIDAPP.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrFileIO


SAMPLE: DDEML Samples Using Microsoft Foundation Classes

Article ID: Q92829

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

CDDEML is a set of two sample applications that demonstrate a DDEML client

and a DDEML server. They are written using the Microsoft Foundation Class

Libraries (MFC) and define new classes for handling DDEML.

Download CDDEML.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for CDDEML.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CDDEML.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CDDEML.EXE

MORE INFORMATION

================

This sample contains two applications that demonstrate a DDEML server and

DDEML client in MFC applications. This sample defines four new classes to

help implement the DDEML support. These classes are:

   CDDEClient

   CDDEClientConv

   CDDEServer

   CDDEServerConv

The CDDEClient and CDDEServer classes encapsulate the functionality of a

DDEML client or server. CDDEClientConv and CDDEServerConv encapsulate

individual conversations that are managed by the CDDEClient or CDDEServer

class. The CDDEClient and CDDEServer classes maintain a map of the current

conversations according to the conversations handle. Using this map, the

server or client can look up any ongoing conversation based on its handle.

These classes were designed to implement DDEML in a very general way. As a

result, these classes don't do much by themselves; they are designed to be

reused in an application by deriving from each of these classes. Typically,

an application derives one class from CDDEClient or CDDEServer. This

derived class contains details such as what conversations are supported and

how to handle callbacks that do not relate to a specific conversation.

Usually there is only one instance of this class in an application. An

application may derive many classes from CDDEClientConv or the application

supports. These derived classes implement how each conversion handles

callbacks. They also may contain buffers to store data from the

conversation, or pointers to other objects that they need to communicate

with. This sample contains a client and server application built using the

classes mentioned above.

One difficulty in writing DDEML classes is how to handle the DDEML callback

function. In this sample, the DDEML callback function is contained in the

CDDEClient or CDDEServer class. The callback function first checks to see

whether the transaction is for the client or server, or for one of the

conversations. If it is for the client or server, then the callback

function calls the member function that handles that transaction. If the

transaction is for a conversation, then the callback function looks up the

pointer to the conversation object using the handle of the conversation in

the conversation map. Then it calls the member function of the conversation

that handles that transaction. Therefore, by using these classes, an

application developer does not need to write a DDEML callback function.

Additional reference words: 3.00 3.10 softlib CDDEML.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Infinite Loop When Moving Through Dialog Box Control

Article ID: Q92905

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

An application enters an infinite loop when you use the TAB or arrow keys

to navigate through dialog box controls. The problem occurs only when the

dialog box has another dialog box as a child. When you use the TAB key, the

problem occurs only when the child dialog box has the WS_MAXIMIZEBOX or

WS_TABSTOPS style.

This article describes the problem in detail together with two possible

solutions. A sample is also provided that demonstrates the problem and one

of the workarounds.

SYMPTOMS

========

Problem 1

---------

When arrow keys are used to maneuver through a dialog box's last control

(the last control in the parent dialog box), the focus is passed to the

next child (in this case, the child dialog box) and the application goes

into an infinite loop.

Problem 2

---------

When the TAB key is used to maneuver through the dialog box's last control,

the focus is then passed to the next child (again the child dialog box) and

the application goes into an infinite loop.

The infinite loop is clearly visible when spying on the child dialog box

window. The child dialog box window continually receives WM_GETDLGCODE

messages.

CAUSE

=====

The dialog box manager confuses the child dialog box window with a child

control.

When maneuvering through controls in a dialog box, the dialog box

manager looks through its children and checks for the next child to pass

focus to. In order to do that, the dialog box manager sets the focus to

the child control and generates messages to complete the process.

Using the Arrow Keys to Navigate Through Controls

-------------------------------------------------

WS_GROUP defines the start of a group within a dialog box. All controls

defined between two WS_GROUP styles are members of a group. Arrow keys can

then be used to navigate between members of a group.

Normally a dialog box does not have WS_GROUP for a style; therefore, the

child dialog box does not have a WS_GROUP but a previous control does have

one. Based on the definition of a group, the child dialog box is considered

a member of the last group by the dialog box manager. When the arrow key is

used on the last control, the dialog box manager checks for the next child

control in that group to pass the focus to, in this case the child dialog

box window. The dialog box manager then tries to set focus to the window

and generates necessary messages to complete the process. These generated

messages are meaningful to a control but not to a window. One of these

generated messages is WM_GETDLGCODE, which causes the infinite loop.

Using the TAB Key to Navigate Through Controls

----------------------------------------------

WS_TABSTOPS defines which control has a tab stop. When you tab through

controls, the dialog box manager looks for the next child that has the

WS_TABSTOPS style and changes the focus to that child.

Normally a dialog box does not use WS_TABSTOPS for a style. It is quite

normal, however, to use WS_MAXIMIZEBOX for a dialog box style. The child

dialog box in this case has WS_MAXIMIZEBOX. The values for WS_TABSTOPS and

WS_MAXIMIZEBOX are the same in WINDOWS.H. Because the dialog box manager

expects a child control and not another window, the WS_MAXIMIZEBOX is

interpreted as WS_TABSTOPS. So, when you tab on the last control of the

parent dialog box, the dialog box manager tries to set the focus to the

next child with WS_TABSTOPS, in this case the child dialog box. Then the

dialog box manager generates the necessary messages to complete the

process. These generated messages are meaningful to a control but not to a

window. One of these messages is WM_GETDLGCODE, which causes the infinite

loop.

RESOLUTION

==========

Workarounds are described in the MORE INFORMATION section below.

MORE INFORMATION

================

 - Do not include the WS_MAXIMIZEBOX style for the child dialog box to

   resolve the TAB key problem, and add WS_GROUP to the child dialog box to

   resolve the arrow key problem.

 - Subclass the last control and handle the change of focus in the dialog

   box. This method is outlined below:

   1. Subclass the last control in the parent dialog box.

   2. In the subclass procedure for the control, process the WM_GETDLGCODE

      message by:

      a. Passing the WM_GETDLGCODE to the button window procedure.

      b. Or'ing the return value of (a.) with DLGC_WANTMESSAGE and

         returning it.

      The following is sample code demonstrating the WM_GETDLGCODE message:

         lpButtonProcOrg is a pointer to the button window

         procedure. This is a global and was set before setting

         the pointer to the subclass procedure for the button.

         To do this call:

                  lpButtonProgOrg = (FARPROC)

                  GetWindowLong(GetDlgItem(hCancelBtn,GWL_WNDPROC);

                  :

                  :

           case WM_GETDLGCODE:

             lRet = CallWindowProc(lpButtonProcOrg,hWnd,iMessage,

                                   wParam,lParam);

             if (lParam)

               {

               lpmsg= (LPMSG) lParam;

               if (lpmsg->message == WM_KEYDOWN)

                {

                if ( (lpmsg->wParam == VK_TAB)   ||

                     (lpmsg->wParam == VK_DOWN)  ||

                     (lpmsg->wParam == VK_UP)    ||

                     (lpmsg->wParam == VK_RIGHT) ||

                     (lpmsg->wParam == VK_LEFT) )

                  lRet |= DLGC_WANTMESSAGE;

                }

               }

             return (lRet);

      For more information on WM_GETDLGCODE, please see the following

      article in the Microsoft Knowledge Base:

         ARTICLE-ID: Q83302

         TITLE     : Using the WM_GETDLGCODE Message

   3. In the subclass procedure, process the WM_KEYDOWN message by:

      a. Set the focus to the first control.

      b. If the first control is not a push button, then the process is

         complete; otherwise, the dark border needs to be removed from

         whichever button that has it, and placed on the first button, as

         follows:

         1) First send a WM_GETDLGCODE.

         2) If the return value is DLGC_DEFPUSHBUTTON, then send a

            BM_SETSTYLE message to the button that has the dark border,

            with BS_PUSHBUTTON for wParam. This will cause the dark border

            to be removed.

         3) Now the dark border needs to be placed on the button that has

            the focus (that is, the first button). To do this, send

            BM_SETSTYLE to the first button, with BS_DEFPUSHBUTTON for

            wParam.

      Sample Code Demonstrating the WM_KEYDOWN Message

      ------------------------------------------------

         case WM_KEYDOWN:

            // Check for keys that need this processing such as the

            // TAB and arrow keys.

            if ( (wParam == VK_TAB)   ||

                 (wParam == VK_DOWN)  || (wParam == VK_UP) ||

                 (wParam == VK_RIGHT) || (wParam == VK_LEFT) )

               {

               // Set the focus to the first control, Button #1

               // in this case.

               hwndBtn1 = GetDlgItem(hParentDlg,IDBUTTON1);

               SetFocus(hwndBtn1);

               // Loop through all the controls and remove the

               // dark border that the previous default push

               // button has.

               hwndCtrls = GetWindow(hParentDlg, GW_CHILD);

               while (hwndCtrls)

                   {

                   wRet = (WORD)(DWORD)SendMessage(hwndCtrls,

                                           WM_GETDLGCODE, 0, 0L);

                  if (wRet & DLGC_DEFPUSHBUTTON)

                    SendMessage(hwndCtrls, BM_SETSTYLE,

                               (WPARAM)BS_PUSHBUTTON, TRUE);

                  hwndCtrls = GetWindow(hwndCtrls, GW_HWNDNEXT);

                  }

              // Give the hwndBtn1 button the default push button

              // border.

               SendMessage(hwndBtn1,  BM_SETSTYLE,

                           (WPARAM)BS_DEFPUSHBUTTON, TRUE);

               return(0L);

               }

            break;

DLGTAB is a file in the Microsoft Software Library that demonstrates both

the TAB and ARROW key problems, together with the second method of

resolving the problem, which is listed above.

Download DLGTAB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLGTAB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLGTAB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLGTAB.EXE

To get the dialog boxes, from the File menu, choose Dialog Tab. Two dialog

boxes will be displayed: one is the Parent dialog box and the other is the

Child dialog box.

There are two option buttons in the Parent dialog box: one demonstrates the

problem and the other the solution. When the Demo Problem option button is

selected, the sample demonstrates the problem. When the Fix Problem option

button is selected, the sample demonstrates the workaround. The default

button is the workaround for the problem.

Additional reference words: 3.10 softlib DLGTAB.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Code Implementing a Child Window with Menus

Article ID: Q93199

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Child windows by design do not have menus; however, some applications

may require such child windows. CHILDMNU demonstrates one way to embed

a pop-up window with menus in a child window to simulate a child

window with menus.

Download CHILDMNU.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for CHILDMNU.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download CHILDMNU.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get CHILDMNU.EXE

MORE INFORMATION

================

Child windows were not designed to have menus but under certain

circumstances an application may require a child window with menus.

Below are the steps to simulate a child window with menus:

1. Create the child for a main window using standard methods.

2. Create a pop-up window without a caption or border. The pop-up

   window should take up the entire client area of the child window.

3. Moving: Set the child window as the parent of the pop-up window

   using SetParent(). This method clips the pop-up window to the

   child's client and moves the pop-up window relative to the child

   window when the child moves.

4. Sizing: If the child window has sizing borders, then the pop-up

   window must be adjusted as the child is sized.

   Correct sizing of the pop-up window can be accomplished by

   processing the child window's WM_SIZE message. When the child

   window receives a WM_SIZE message, the child's new client area is

   calculated and the pop-up window is adjusted.

5. Activation: Child windows are not activated by design. When the

   user clicks the pop-up window, activation is taken away from the

   main window and is given to the pop-up window. To simulate the main

   window's activation, the pop-up's window procedure, upon receiving

   a WM_ACTIVATE message, posts a WM_NCACTIVATE message to the main

   window.

   Note: This step causes flashing because the caption is repainted

   when going back and forth between the pop-up window and the main

   window. Unfortunately, there is no sure way to accomplish the

   change of caption's activation.

Other Considerations

--------------------

Maximizing: When a child window is maximized, it uses the screen's

maximum size. To have the child window act similar to an MDI child,

two messages need to be processed; WM_SIZE in the main parent's window

procedure and WM_GETMINMAXINFO in the child's window procedure.

WM_SIZE of the child's parent window procedure checks for

SIZE_MAXIMIZE and SIZE_RESTORE. Then, if the child window is

maximized, call ShowWindow() with SW_MAXIMIZED. This method adjusts

the child window's size to the new size of the parent's client area.

On WM_GETMINMAXINFO of the child's window procedure, calculate the size

of the parent's client area. Use the newly calculated size and set the

ptMaxSize variable of the MINMAXINFO structure. This ensures that the

child is always fully contained within its parent client area when

maximized.

Additional reference words: 3.10 softlib CHILDMNU.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMen


SAMPLE: Bitmap Manipulation Techniques

Article ID: Q94691

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Windows versions 3.0 and 3.1 bitmap-manipulation application

programming interface (API) (BitBlt(), StretchBlt(), StretchDIBits(), and

so forth) contains a powerful complement of raster operations (ROP) that

allow for complicated handling of bitmaps. These raster-operation codes can

be used, for example, to change an entire color in a bitmap without

affecting the other colors.

The BMUTIL sample in the Microsoft Software Library demonstrates the

following bitmap manipulation techniques:

1. Creating an unavailable or disabled (grayed) bitmap from a color bitmap

   using various ROP codes and the BitBlt() function.

2. Changing a single color in a bitmap without affecting any other colors.

   This is implemented completely using BitBlt() with various raster-

   operation (ROP) codes.

3. Swapping two colors in a bitmap without affecting any other colors. This

   is also implemented with BitBlt() and ROP codes.

4. Dithering a color bitmap to a monochrome bitmap. This is done by

   manipulating the bits of a device-independent bitmap (DIB) directly.

This sample uses the Windows 3.1 common dialog boxes, so you must have the

Windows 3.1 SDK to compile it.

Download BMUTIL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S13961.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BMUTIL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BMUTIL.EXE

Additional reference words: 3.00 3.10 softlib BMUTIL.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Copying a File

Article ID: Q95333

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

COPYTEST is a sample that contains a complete code module to copy a file of

any size and set its file date/time stamp.

Windows contains its own set of file I/O functions to perform the basic

operations such as file open, close, read, write, and so forth; however,

there is no function to copy a file. The COPY.C module included in this

sample can be plugged into any application or dynamic-link library (DLL).

Download COPYTEST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for COPYTEST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download COPYTEST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get COPYTEST.EXE

Some of the features of this module are:

 - The ability to rename the output file

 - The ability to copy the file date/time stamp and attributes

 - Nondependency upon the C run time due to the use of inline assembly

 - Robust error reporting

For information on how to call the CopyFile() function, please refer

to the comment block inside of COPY.C.

Additional reference words: 3.00 3.10 softlib COPYTEST.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrFileIO


SAMPLE: DLL Which is Callable from Microsoft Setup Script

Article ID: Q95937

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

----------------------------------------------------------------------

FILEEDIT demonstrates how to create a function in a dynamic-link library

(DLL) that is callable from a Microsoft Setup installation script. The

entry function, FileEditDialog, takes the handle to Setup's frame window

and a long pointer to a filename. FILEEDIT opens the file and places its

contents in a read-only edit control. The function then adds the line "REM

New File" to the beginning of the file and displays the updated file in a

list box. Thus, the user can view both the old file and the proposed

updated file at the same time. The user can update the contents of the new

file by selecting lines within the list box. When the user has completed

updating the file, the file can be saved using the common dialog boxes. If

the file is successfully saved, FILEEDIT creates an entry (FILEEDIT) in the

global symbol table with the saved filename.

A modified version of the SAMPLE1.MST script file is included to

demonstrate how to call into the FILEEDIT DLL. Additionally, the script has

been updated to get the symbol FILEEDIT and display the saved filename in a

message box.

Download FILEEDIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FILEEDIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FILEEDIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FILEEDIT.EXE

Additional reference words: 3.10 FILEEDIT.EXE softlib

KBCategory: kbprg kbfile

KBSubcategory: TlsMss


SAMPLE: Windows Application to Unload DLLs from Memory

Article ID: Q96312

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

During development, dynamic-link libraries (DLLs) can sometimes be left in

memory with no applications using them. To unload DLLs that have been left

in memory, developers must exit and then restart Windows, which can be very

inconvenient. DLL UNLOADER is a sample Windows-based application that lets

developers select a DLL, show information about it, and unload it from the

system if desired; this eliminates the need to restart Windows.

Download UNLOADER.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for UNLOADER.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download UNLOADER.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get UNLOADER.EXE

MORE INFORMATION

================

There are two ways that a DLL can be left in memory after all

applications that use it have exited:

 - The application loads a DLL by calling LoadLibrary() and doesn't call

   FreeLibrary to unload it.

 - The application causes a general protection (GP) fault and is

   terminated by Windows.

Either of these occurrences can cause difficulties for developers. For

example:

If a DLL is left in memory with no application using it, and is then

recompiled and executed, the new version of the DLL will not be loaded

because Windows thinks the DLL is already loaded (because the module names

are the same). If you try to debug the DLL with CodeView for Windows, the

source code window will display the latest version's source code; however,

the old version's code, which is still in memory, will be executed. This

version mismatch causes CodeView to appear to not be working properly. To

resolve this problem, you must either exit and restart Windows or force

Windows to unload the old version of the DLL.

The DLL UNLOADER sample calls ToolHelp to obtain the list of modules

currently loaded in the system. Because this list contains modules that

belong to both DLLs and applications (which are tasks), DLL UNLOADER

filters out the modules that belong to tasks so that they cannot be

unloaded accidentally and cause the system to crash. The list box stores

the module name and handle for each module that doesn't belong to a task.

When the user selects a module, its handle is used to obtain information

about it and/or unload it.

To unload a DLL, DLL UNLOADER first calls GetModuleUsage() to retrieve its

usage count and then repeatedly calls FreeLibrary() until the usage count

drops to zero; then Windows unloads the DLL. To obtain information about a

DLL, DLL UNLOADER calls ModuleFindHandle() and displays the information in

a dialog box.

Finally, DLL UNLOADER creates an .INI file in the directory where its

executable file resides to remember its last position on the screen before

it exits.

Additional reference words: 3.10 softlib UNLOADER.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: Windows Code Module to Delete Files

Article ID: Q96789

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The DELTEST sample contains a complete code module to delete one or more

files by using wildcards. The sample also demonstrates how to use wildcards

to search through an entire directory.

Download DELTEST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DELTEST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DELTEST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DELTEST.EXE

MORE INFORMATION

================

The C Run-time contains a function to delete one file, but does not allow a

program to delete multiple files using wildcard characters. The DELETE.C

module included with this sample can be used with any application or

dynamic-link library (DLL) to perform this operation. This module uses the

_dos_findfirst/next functions in conjunction with the remove() function to

allow multiple files to be erased.

NOTE: In the sample, if "Delete tmp Files" is selected from the menu,

the two .TMP files included with the sample will be erased.

For information on how to call the Delete() function, please refer to

the comment block inside of DELETE.C.

Additional reference words: 3.00 3.10 softlib DELTEST.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrFileIO


SAMPLE: DRAGBMP Demonstrates Dragging Bitmaps on the Screen

Article ID: Q97188

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

DRAGBMP shows how to drag images smoothly on the screen. This is achieved

through the use of several bitmaps and a series of BitBlt operations.

Before you can drag a bitmap, you must store the following information:

1. A bitmap of the desired image, such as the cards in Solitaire or

   the domino used in this sample.

2. A bitmap of what lies underneath the desired image. This

   information is necessary to redraw the underlying area when the

   image is dragged elsewhere.

3. The current position of the image (you can also store or retrieve

   the width and height of the image using GetObject() in the image's

   bitmap).

Once this information is stored, the image is ready to drag. The user

selects the image by clicking the left mouse button when the mouse pointer

is on the image, drags the image by moving the mouse while the mouse button

is depressed, and ends the dragging by releasing the mouse button.

In this sample, the image is a yellow domino. Choose Draw Image! to draw

the domino, then drag the domino using the mouse. Hit-testing in

WM_LBUTTONDOWN determines when the domino is selected. Once selected, the

dragging process begins. On each WM_MOUSEMOVE, a new background bitmap is

created, the old background bitmap is restored, and the domino is moved to

its new location. The WM_LBUTTONUP message ends the dragging process.

(x',y')

+------------------------- new position

|\                       |

| \(dx,dy)               |

|  \                     |

|   + . . . . . . . . . . . . . . . . . old position

|   .(x,y)               |            .

|   .                    |            .

|   .                    |            .

----.---------------------            .

    .                                 .

    .                                 .

    . . . . . . . . . . . . . . . . . .

The basic steps to perform the bitmap dragging are as follows:

1. Calculate the delta x and delta y in the mouse movement (dx,dy).

2. BitBlt() the screen at the new position onto a new bitmap. This

   corresponds to a rectangle with origin at (x',y') in the figure

   above, and becomes the new background bitmap.

3. Since the new background bitmap still contains part of the domino's

   image starting at point (x,y) in the figure above, BitBlt() the old

   background bitmap to that point on the new background bitmap,

   offsetting it by dx and dy. The resulting bitmap contains the

   correct background for the new position.

4. BitBlt() the domino's bitmap to the screen at its new location:

   origin at point (x',y') in the figure above.

5. The domino is now in the correct position on the screen and we have

   a bitmap of what is underneath, but a portion of the domino still

   appears at the lower right. To erase this portion, first BitBlt() the

   bitmap of the domino onto the old background's bitmap, offsetting

   it by -dx and -dy, and then BitBlt this modified old background

   bitmap to the screen at point (x,y). This erases the old portion of

   the domino without flashing.

6. Dragging is now complete. Store the new background bitmap and

   delete the old one.

The DRAG.C file contains the code for dragging and hit-testing. The

MAINWND.C file contains the code for processing the mouse and paint

messages.

DRAGBMP was built and tested under Microsoft Windows version 3.1.

Download DRAGBMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S14044.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DRAGBMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DRAGBMP.EXE

Additional reference words: 3.10 softlib DRAGBMP.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: FADE Demonstrates Fading Bitmaps w/ Pallette Animation

Article ID: Q97189

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

FADE: Fades Bitmaps Using Palette Animation

FADE loads, generates, saves, and "fades" special device-independent

bitmaps (DIBs) built from two component DIBs. The fading technique

involves animating a palette matrix built from the two component

palettes. For more information, see the README.TXT file.

The dual DIBs created by FADE are 8 bytes per pixel (bpp) but the

component DIBs must be 4 bpp. FADE automatically converts monochrome

DIBs to 4 bpp before building the resultant DIB, but prompts you

before converting higher-resolution DIBs down to 4 bpp. (This

conversion does not include color analysis.)

FADE depends on the Microsoft(R) Windows(TM) palette and will not run

if the video display does not support palettes. For example, FADE does

not run on a standard VGA display, but runs on most 256-color

displays.

To see the application in action, open one of the .BM2 files included

with FADE and manipulate the scroll bar and animation settings. (Keep

in mind that what you see has nothing to do with BitBlt's.)

Download FADE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FADE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FADE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FADE.EXE

Additional reference words: ScreenToClient; MoveWindow; softlib FADE.EXE

CreatePalette; SelectPalette; RealizePalette; CreateCompatibleDC;

GetStockObject; AnimatePalette; InflateRect; CreateSolidBrush; PatBlt;

GetNearestColor; GetSysColor; CreateDIMap; GetDIBits;

CreateDIBPalette; DIBToBitmap; _lread; _hread; _lclose;

SetSystemPaletteUse

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: GDIWATCH Uses Tool Helper Library to Walk Heap

Article ID: Q97190

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

GDIWATCH: Uses Tool Helper Library to Walk Heap

GDIWATCH shows how to use the functions in the tool helper library

(TOOLHELP.DLL) to walk the graphics device interface (GDI) and User

local heaps.

The DLL exports a very primitive application programming interface. It

contains the following two functions:

   void FAR PASCAL TakeSnapShot(HWND hWndParent, int

   iHeapMarker);

   void FAR PASCAL Compare(HWND hWndParent, int

   iHeapMarker,

   int iNewMessage);

Do not mismatch IDM_GDIHEAP and IDM_USERHEAP when using TakeSnapShot

and Compare; it will produce random garbage data. All identifiers are

defined in WATCHLIB.H.

GDIWATCH was built and tested under Microsoft(R) Windows(TM) version

3.1.

Download GDIWATCH.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GDIWATCH.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GDIWATCH.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get GDIWATCH.EXE

Additional reference words: PR-CD2; CreateFontIndirect LocalFirst softlib

GDIWATCH.EXE

LocalNext LocalLock LocalUnlock

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: RLEAPP Demonstrates Animations Using DIB RLE Format

Article ID: Q97192

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

RLEAPP loads, generates, plays and saves animations using the

device-independent bitmap (DIB) run-length encoding (RLE) format for

delta frames.

The RLE format is described in the following documentation:

 - The Microsoft(R) Windows(TM) version 3.0 Software Development Kit

   (SDK): "Reference--Volume 1," in the section on the

   BITMAPINFOHEADER structure.

 - The Microsoft Windows version 3.1 SDK: "Programmer's Reference,

   Volume 3: Messages, Structures, and Macros," in the section on

   BITMAPINFOHEADER.

RLEAPP handles only 8-bits-per-pixel DIBs, although the same

technology applies to 4-bits-per-pixel DIBs (RLE, delta frame, and so

on).

RLEAPP source code includes many optimizations for 80386-specific

machines. This is a very useful way to increase speed because the MPC

specification calls for a machine that uses a 80386 or higher

processor, so in most cases, the 80286 support can be left out.

RLEAPP is very dependent on the BitBlt() speed of the video card and

driver. In most cases, the video driver is very slow doing BitBlt.

Comments on speed should be directed to the video card manufacturer,

who is responsible for this code. The speed to BitBlt() a 160x120

256-color frame (with the same palette) is approximately 15 frames per

second. The BitBlt() speed for slow drivers or cards is about 1 frame

per second.

RLEAPP was built and tested under Microsoft Windows version 3.1.

Download RLEAPP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RLEAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RLEAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RLEAPP.EXE

Additional reference words: 3.10 softlib RLEAPP.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: WINCAP Captures Screens Using DIB API

Article ID: Q97193

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

WINCAP demonstrates how to capture, save, and print the entire screen,

portions of the screen, or specific windows. The program also defines

routines that accomplish common device-independent bitmap (DIB)

functions; these routines form the DIB application programming

interface (API). WINCAP uses the DIB API functions for most of the

screen capture, printing, and saving work. See the DIBAPI.TXT file for

a description of the DIB API functions.

MORE INFORMATION

================

WINCAP illustrates the following techniques:

 - Capturing the screen (or a specific window) into a DIB

 - Capturing the screen to a device-dependent bitmap (DDB)

 - Printing a DIB using banding

 - Loading and saving a DIB to a disk file (.BMP file)

 - Converting between DIBs and DDBs

 - Displaying the captured screen DDB

All of these techniques call the DIB API. WINCAP includes the source

code for these functions. You can call these functions easily from a

different application by simply compiling the enclosed DIBAPI.DLL, and

linking with the DIBAPI.LIB import library.

The preferred way to capture a screen in Microsoft(R) Windows(TM) is

to copy the screen pixels into a DIB, and then to use this DIB in

subsequent operations (for example, to save the bitmap to a file or

print the bitmap).

If you do not use a DIB in the intermediate step, the results of the

screen print may be less than desirable. If you use a DIB to hold the

screen image, device-dependent information is removed from the bitmap.

This simplifies the process of displaying the image on devices with

different display capabilities. For example, capturing a screen from

a 24-bit display adapter and printing it on a 1-bit (monochrome)

printer can produce exceptional results if DIBs are used.

Additionally, many printer drivers implement gray-scale dithering; the

output on these printers is also excellent when DIBs are used.

NOTE: Because bitmaps are device-dependent, you should avoid the

BitBlt function when printing bitmaps. The type of bitmaps that the

BitBlt function requires are normally in the format of the display

driver rather than the printer driver. Depending on the drivers

involved, the results of using BitBlt to print a bitmap can vary from

extremely poor output quality to no output at all.

Although all printer drivers are able to BitBlt a monochrome bitmap to

the printer, this technique generally produces poor results because

the printer cannot apply gray-scaling to the image.

This technique of using a DIB to convert a bitmap between display

devices with different capabilities can also be used to convert

bitmaps while preserving the original color information (for example,

loading a 256-color bitmap from a .BMP file and printing it to a

3-color printer or displaying it on a 24-bit display).

The file DIBAPI.TXT contains more information on function parameters

and usage. A Windows Help file for the DIB APIs is also included.

Download WINCAP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINCAP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINCAP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINCAP.EXE

Additional reference words: 3.00 printscreen 3.10 softlib WINCAP.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: MAKEAPP Demonstrates Using WINDOWS.H STRICT Option

Article ID: Q97195

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

MAKEAPP: Generates a Microsoft Windows-based Application

MAKEAPP illustrates the use of the WINDOWS.H STRICT option and

provides examples of the following WINDOWSX.H features: message

crackers, control functions, and macro functions.

You can run the MAKEAPP.BAT batch file to create a new

Windows(TM)-based application. MAKEAPP changes the names of files,

constants, and functions to names that you specify and creates a clone

of the MAKEAPP application project. For more information, see the

MAKEAPP.TXT and WINDOWSX.TXT files.

MAKEAPP was built and tested under Microsoft(R) Windows version 3.1.

Download MAKEAPP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MAKEAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MAKEAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MAKEAPP.EXE

Additional reference words: 3.10 softlib MAKEAPP.EXE

KBCategory: kbprg kbfile

KBSubcategory: TlsMisc


SAMPLE: MFCDIB Demonstrates Defining a DIB with MFC

Article ID: Q97196

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

MFCDIB: Defines a DIB Using MFC

MFCDIB is a Microsoft(R) Foundation Class (MFC) sample that

demonstrates a technique for implementing a CDIB class. The CDIB class

defines an object that represents a device-independent bitmap (DIB).

MFCDIB can load, save, display, copy, paste, and serialize a CDIB

object.

The CDIB class is derived from CObject. The CDIB class is implemented

by calling prewritten C routines from the DIBUTIL.DLL library, which

contains many high-level functions for DIB manipulation.

MFCDIB requires Microsoft C/C++ version 7.0 and the Microsoft

Windows(TM) version 3.1 Software Development Kit (SDK) libraries.

Download MFCDIB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MFCDIB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MFCDIB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MFCDIB.EXE

Additional reference words: 3.10 softlib MFCDIB.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: SHOWGRP Demonstrates Reading Group Files

Article ID: Q97197

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SHOWGRP: Reads Group Files

SHOWGRP demonstrates how to read group files. The group file format is

documented in the Microsoft(R) Windows(TM) version 3.1 Software

Development Kit (SDK) "Programmer's Reference."

Download SHOWGRP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SHOWGRP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SHOWGRP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SHOWGRP.EXE

Additional reference words: 3.10 softlib SHOWGRP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrExt


SAMPLE: WINQUERY Demonstrated SQL Server Queries

Article ID: Q97199

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

WINQUERY: Demonstrates SQL Server Query

WINQUERY demonstrates ad-hoc queries in Microsoft(R) SQL Server. It

multitasks to do background query processing using a PeekMessage loop.

WINQUERY requires three SQL Server files to build, and two SQL files

to run. The three SQL Server include files come with the SQL Server

Programmer's Toolkit for C: SQLFRONT.H, SQLDB.H, and W3DBLIB.LIB along

with the two SQL Server run-time files:W3DBLIB.DLL and DBNMP3.DLL.

WINQUERY was built and tested under Microsoft Windows(TM) version 3.1

and SQL Server PTK for C version 4.2 A.

Download WINQUERY.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINQUERY.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINQUERY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINQUERY.EXE

Additional reference words: 3.10 softlib WINQUERY.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMsg


SAMPLE: XTENSION Demonstrates a File Manager Extension DLL

Article ID: Q97200

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

XTENSION: Extension DLL for File Manager

XTENSION is an extension dynamic-link library (DLL) that adds

administration support features such as file and disk utilities to

Microsoft(R) Windows(TM) File Manager. XTENSION contains an entry

point to process menu commands and notification messages sent by File

Manager and can retrieve information about File Manager windows.

XTENSION adds a menu called Extension to File Manager and processes

all messages that File Manager sends to an extension DLL. It also

creates a status window using the DLL's instance handle and adds the

following commands to the File Manager Extension menu:

 - Status Window: Shows/hides status window.

 - Selected File(s) Size: Displays disk space taken by the files.

 - Selected Drive Info: Displays selected drive information.

 - Focused Item Info: Displays the name of the selected item.

 - Reload Extension: Reloads this extension.

 - Refresh Window: Refreshes File Manager's active window.

 - Refresh All Windows: Refreshes all File Manager windows.

 - About Extension: Displays About dialog box.

To load XTENSION.DLL as a File Manager extension, add the following

lines to the WINFILE.INI initialization file:

   [AddOns]

   SDK Demo Extension=<path to XTENSION.DLL>

File Manager installs the extensions that have entries in the [AddOns]

section of WINFILE.INI. Each entry consists of a tag and a value.

The File Manager extensions are new in Microsoft Windows version 3.1.

For information on relevant functions and messages, see the Windows

version 3.1 Software Development Kit (SDK) "Programmer's Reference"

manual.

Download XTENSION.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for XTENSION.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download XTENSION.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get XTENSION.EXE

Additional reference words:  3.10 FMExtensionProc; FM_GETFOCUS; softlib

XTENSION.EXE

FM_REFRESH_WINDOWS; FMEVENT_INITMENU; FMEVENT_LOAD; FMEVENT_SELCHANGE;

FMEVENT_UNLOAD; FMEVENT_USER_REFRESH; FMS_GETDRIVEINFO; FMS_GETFILESEL

KBCategory: kbprg kbfile

KBSubcategory: UsrExt


SAMPLE: BADAPP Intentionally Forces a GP-Fault or Hang

Article ID: Q97201

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

BADAPP: Demonstrates "Bad Application" Handling

BADAPP is an application designed for Microsoft(R) Windows(TM)

versions 3.0 and 3.1 that can generate a GP fault and hang after

receiving input. Its purpose is to demonstrate how Windows version 3.1

handles "bad applications."

WARNING: Before running BADAPP, save your work and close all other

applications to avoid any problems that the GP fault or hang may

cause.

When you choose GP-Fault or Hang from the Action menu, the "fuse" in

the display area burns down before the GP fault occurs. If you have a

multimedia system, the burning fuse will be accompanied by sound

effects. You can choose Options from the Action menu to disable the

sound, to modify the zoom factor, and to change the visible

application title (limited to eight characters).

BADAPP was built with Microsoft QuickC(R) version 1.0. The fuse icons

were created using the IconWorks sample application from Visual

Basic(TM) version 1.0. ICO2BMP.EXE was used to convert the FUSE*.ICO

and BOOM*.ICO files to FUSE*.BMP and BOOM*.BMP files.

Download BADAPP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BADAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BADAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BADAPP.EXE

Additional reference words: 3.10 softlib BADAPP.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDebug


SAMPLE: FAULT Demonstrates Exception and Fault Trapping

Article ID: Q97204

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

FAULT: Demonstrates Exception and Fault Trapping

FAULT demonstrates a method for trapping divide-by-zero exceptions and

general protection (GP) faults in a retail application. It also shows

how to recover from these problems using the Catch and Throw functions

in Microsoft(R) Windows(TM). Instead of forcing the user to terminate,

the application can quietly recover from the problem and fail the

operation, if at all possible. FAULT is a companion program for the

"Bulletproof Functions With ToolHelper" technical article on the

Microsoft Developer Network CD.

The ability to trap exceptions gives an application considerable power

and responsibility. ToolHelper lets you trap all exceptions, including

Interrupt 3 (debug breakpoints) and the CTRL+ALT+SYSRQ key sequence.

Some exception-handling techniques (for example, debugging interrupts)

should never be used in a retail product. However, these techniques

let you perform minor cleanup, error logging, and similar tasks

without user intervention and without terminating the application in

the debugging version of your application.

Download FAULT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FAULT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FAULT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FAULT.EXE

Additional reference words: 3.10 InterruptRegister InterruptUnRegister

softlib FAULT.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: ISHANDLE Demonstrates Validating Handles

Article ID: Q97205

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

HANDLE and ISHANDLE: Validate Global and Local Handles

This sample consists of two components:

 - ISHANDLE.DLL is a dynamic-link library (DLL) that exports two

   functions, IsGlobalHandle and IsLocalHandle, which validate global

   and local handles.

 - HANDLE.EXE is an application that tests these two functions by

   linking into the DLL.

The IsLocalHandle and IsGlobalHandle functions in ISHANDLE.DLL use a

set of functions from TOOLHELP.DLL to validate the given local or

global handle. IsLocalHandle uses the LocalFirst and LocalNext

functions to walk the local heap until the desired local handle is

found. Similarly, IsGlobalFunction uses the GlobalFirst and GlobalNext

functions to walk the global heap until the desired global handle is

found.

HANDLE demonstrates the IsLocalHandle and IsGlobalHandle functions by

passing good and bad handles to these functions.

The following code shows how IsLocalHandle walks the local heap and

validates the given local handle, hLocalHandle:

/* Declare local variables. */

LOCALENTRY LEntry;

/* Allocate a buffer to do the local heap walk. */

bFound = FALSE;

LEntry.dwSize = sizeof(LOCALENTRY);

/* Loop through the local heap until hLocalHandle is

found. */

if (LocalFirst(&LEntry, wHeap))

{

do

{

if (LEntry.hHandle == hLocalHandle)

{

bFound = TRUE;

break;

}

} while (LocalNext(&LEntry));

}

if (bFound)

return hLocalHandle;

else

return NULL;

You can adopt this idea to walk the local/global heap and obtain/store

more information on a block of memory from the LOCALENTRY and

GLOBALENTRY structures. For example, you can build a dynamic list that

maintains information about the heaps, or use the DLL to simulate the

functionality of the TOOLHELP ModuleFindHandle and TaskFindHandle

functions.

HANDLE requires Microsoft(R) Windows(TM) version 3.1 to build, but has

been compiled for 3.1 and 3.0 compatibility. TOOLHELP.DLL was not

shipped with Windows 3.0; you must copy this library to the

\WINDOWS\SYSTEM directory to run HANDLE under 3.0.

Download ISHANDLE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ISHANDLE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ISHANDLE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ISHANDLE.EXE

Additional reference words: 3.10 softlib ISHANDLE.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: MULTAPP is a Multi-Instance DLL with Separate Data

Article ID: Q97206

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

MULTAPP: Multi-Instance DLL with Separate Data

MULTAPP creates a multi-instance dynamic-link library (DLL) that

maintains separate data for each task that links to it. A task is

identified by the value of its stack segment (SS). Data for each task

is stored in a block of memory obtained through GlobalAlloc. When a

task calls a function in the DLL, the DLL looks up the task in its

list and gets the segment (selector) of the global memory block that

contains the data for that task. The segment address is then placed

into the DS register. After this point, all static data and the local

heap are specific to the task that called the DLL.

MULTAPP provides menu options for entering data into the DLL's data

segment, retrieving data from the DLL's data segment, and filling the

local heap with data items.

The first time a task calls into the DLL, a new block of memory is

allocated for the task's data. The initial values for the static

variables are copied into the block and a local heap is initialized.

When a task that has called into the DLL shuts down, it must call the

UnregisterTask function. This function removes the task from the DLL's

list and frees the data associated with the task. If the task does not

call UnregisterTask, another task with the same SS as the first task

might link to the DLL. Since the first task did not unregister itself,

the SS will be associated with a DS that is no longer present, and

will cause a UAE.

Download MULTAPP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MULTAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MULTAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MULTAPP.EXE

Additional reference words: 3.10 LocalReAlloc LocalAlloc LocalLock softlib

MULTAPP.EXE

LocalUnLock GlobalSize GlobalAlloc GlobalLock

3.10

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: MIDIKEYB Demonstrates the midiKeyB Control

Article ID: Q97208

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

MIDIKEYB: Demonstrates the midiKeyB Control

MIDIKEYB is designed to show how to use midiKeyB, which is a custom

control that implements a musical instrument digital interface

(MIDI)-style keyboard. This keyboard is not exactly the best keyboard

for a jam session; don't expect to hit a bunch of hemidemisemiquavers

at correct tempo.

The midiKeyB control responds to and sends short MIDI messages. The

right mouse button is used for "sticky keys" and toggles the state

appropriately.

For more information, see the function headers in the source code.

Download MIDIKEYB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MIDIKEYB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MIDIKEYB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MIDIKEYB.EXE

Additional reference words: 3.10 softlib MIDIKEYB.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: ZYZGAUGE Demonstrates a Progress Bar

Article ID: Q97209

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

ZYZGAUGE: Demonstrates Progress Bar

ZYZGAUGE shows how to use the zYzGauge control. The Gas Gauge Custom

Control in the client window gives you a progress bar class named

zYzGauge. You can set the range, position, font, color, orientation,

and 3-D effect of the gauge by sending messages to the control.

For more information on using the control, please see the header

information in ZYZGAUGE.C.

Download ZYZGAUGE.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ZYZGAUGE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ZYZGAUGE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ZYZGAUGE.EXE

Additional reference words: 3.10 softlib zYZGAUGE.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: GRID Demonstrates Circle Gestures and Much More

Article ID: Q97213

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

GRID is a sample pen application that demonstrates the following features:

 - How to change the shape of a mouse cursor when the state of the

   system changes

 - How to process the REC_POINTEREVENT return code from the Recognize

   function to distinguish between a Tap and a TapNHold

 - How to support a circle gesture

 - How to cut and paste ink to the Clipboard

 - How to operate the correct writing dialog

 - How to use the recognition termination condition of PCM_RECTBOUND to

   allow a user to enter information quickly

GRID was built and tested under Microsoft(R) Windows(TM) version 3.1. The

program requires Microsoft Windows for Pen Computing.

Download FILENAME.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GRID.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GRID.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get GRID.EXE

Additional reference words: 1.00 softlib GRID.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenGestures


SAMPLE: HOTSPOTS Recognizes Hotspots Associated with Gestures

Article ID: Q97214

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

HOTSPOTS is a pen application that helps developers recognize hotspots

associated with gestures. When the user draws a gesture, HOTSPOTS

redisplays the ink using a red pen. If the gesture has a hotspot, the

hotspot is circled with a small black dot. If the input was not a gesture,

it is drawn in black.

HOTSPOTS requires PENWIN.DLL, which can be found in both Microsoft(R)

Windows(TM) for Pen Computing in the Microsoft Windows version 3.1

Software Development Kit (SDK).

HOTSPOTS was built and tested under Microsoft Windows version 3.1. The

program is designed to work with Microsoft Windows for Pen Computing.

Download HOTSPOTS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HOTSPOTS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HOTSPOTS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HOTSPOTS.EXE

Additional reference words: 1.00 softlib HOTSPOTS.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenGestures


SAMPLE: SUBCLASS Subclasses an Edit Control Using MFC

Article ID: Q97216

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUBCLASS: Subclasses an Edit Control Using MFC

SUBCLASS subclasses an edit control in a dialog box and makes it

accept either numbers or letters. SUBCLASS uses five classes inherited

from CEdit, CSubclassedEdit, CModalDialog, CWinApp, and CFrameWnd.

SUBCLASS subclasses a window by replacing the window procedure for

that window with AfxWndProc, and attaching the window to a CWnd

object. MFC provides two functions to subclass a window:

SubclassWindow and SubclassDlgitem. These functions store the old

window procedure in the location returned by GetSuperWndProcAddr.

To change the behavior of the target window, SUBCLASS overloads the

appropriate functions for the CWnd object.

You can change the behavior of a subclassed window by subclassing it

with a different CWnd object. Before calling the subclassing function

on that window, you must first "unsubclass" the window. MFC does not

provide a function to unsubclass a window. You must call

::SetWindowLong to replace the AfxWndProc with the original window

procedure, then detach the CWnd object from the target window.

SUBCLASS subclasses an edit control in a dialog box to accept either

numbers or letters. The CSubclassedEdit class is derived from CEdit,

and UnSubclass is declared as its member function. Two additional

classes (CSubNumberEdit and CSubLetterEdit) are derived from

CSubclassedEdit to provide the two behaviors for the edit control. The

OnChar function is overloaded for both of these classes.

The dialog-box class is derived from CModalDialog and has two member

data objects: SubNumberEdit and CSubLetterEdit.

Download SUBCLASS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SUBCLASS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SUBCLASS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SUBCLASS.EXE

Additional reference words: 3.10 softlib SUBCLASS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: PRESSURE Demonstrates Capturing Pressure Information

Article ID: Q97217

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

PRESSURE demonstrates one way of capturing pressure information from

Microsoft(R) Windows(TM) for Pen Computing using the GetPenHwEventData()

function.

PRESSURE requires PENWIN.DLL, which can be found in both Microsoft Windows

for Pen Computing in the Microsoft Windows version 3.1 Software Development

Kit (SDK). PRESSURE also works on a tablet that has pressure-sensing

capabilities.

PRESSURE was built and tested under Microsoft Windows version 3.1.

MORE INFORMATION

================

Download PRESSURE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PRESSURE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PRESSURE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PRESSURE.EXE

The PRESSURE sample application demonstrates how an application can

capture pressure information from a tablet.

The key information in this application relates to the processing of

the WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_LBUTTONUP messages. When the

sample receives one of these messages, it determines if the message

was generated by the tablet by using the GetMessageExtraInfo() and

IsPenEvent() functions. If so, the sample calls the GetPenHwEventData()

function to retrieve the extra information associated with the message. The

same value is used for the first two parameters of GetPenHwEventData()

because the PRESSURE sample requires information only about a single point.

To retrieve all the information about a series of events, the application

must save the initial event and pass both the initial event and the final

event to GetPenHwEventData().

After PRESSURE retrieves the information from GetPenHwEventData(), it

redraws the needle and updates some internal variables. When PRESSURE

processes the WM_CREATE message, it determines if a tablet capable of

generating pressure information is connected to the system. After the

application loads, a mouse can be used to operate its basic

functionality. The "needle" in the client area will respond only when

a pressure-sensitive pen is used. The application uses the IsPenEvent()

function to determine which device generates particular messages.

On systems with a debugging terminal attached, PRESSURE can display

the current pressure reading on the debug terminal. To access this

functionality, modify the MAINWND.C file to define the DEBUGGING

symbol.

Additional reference words: 1.00 softlib

KBCategory: kbprg kbfile

KBSubcategory: WpenMisc


SAMPLE: RCDUMP Displays the RCRESULT Structure

Article ID: Q97218

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

RCDUMP: Displays RCRESULT Structure

The RCDUMP sample program displays the entire RCRESULT structure and

shows the cause and effect of different RC options in real time.

Developers who are unfamiliar with the Microsoft(R) Windows(TM) for

Pen Computing system can use RCDUMP while reading the pen

documentation to understand the actions of different flags and

settings.

Developers who are implementing recognizers and dictionaries for

Windows for Pen Computing can use RCDUMP to view and test different RC

settings in their system components. RCDUMP allows you to change RC

settings and immediately see the effects of the change.

For more information on RCDUMP, please see the RCDUMP.DOC file.

Download RCDUMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RCDUMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RCDUMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RCDUMP.EXE

Additional reference words: 3.10 softlib

KBCategory: kbprg kbfile

KBSubcategory: TlsRc


SAMPLE: HEALTH is a Visual Basic Pen Healthcare Application

Article ID: Q97220

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

HEALTH: Visual Basic(TM) 1.0 Pen Healthcare Application

HEALTH contains seven forms for admitting and diagnosing a patient in

a healthcare facility. This program is fairly large and unoptimized,

so load times are significant. Tap firmly on the buttons for Next

Page, Previous Page, and so on, and then wait as HEALTH loads each

form.

 - The first form is a Patient Identification form. To complete this

   form, enter numbers in the bedit field, tap the button, then tap

   the appropriate Gender radio button. Do not tap the Enable Entry

   Checking check box in the lower part of the screen--this option

   opens a smart form that won't let you move to the next screen until

   all fields are filled out.

 - The second form is fairly straightforward. Note that if you tap the

   icon, it will reformat and lock that field. For example, after

   entering the date, tap the icon next to it to format the date and

   lock that field.

 - The third form, In Case of Emergency Notify, contains an hedit field

   for medical diagnosis. You can write anything you want in this

   field, but print neatly. The application will try to recognize

   whatever you write.

 - The fourth form, Physical, contains diagrams of the body. You can

   draw on these diagrams to diagnose or highlight any problems. This

   screen takes some time to load, so tap the Next Page icon quickly.

   The ink display rate is good; hold the pen down on the screen for a

   second, and then write as quickly as you like. You can tap the Lock

   icon once to lock the ink, and a second time to clear the screen.

 - The fifth form, Clinical Assessment, contains multiple forms that

   you can fill out to note allergies, hearing and eyesight

   limitations, and so on. To view all forms at once, choose Arrange

   from the top part of the screen. However, having many screens on

   display can intimidate a new user, so we suggest that you fill out

   only the first form. For example:

      1. Tap Hearing.

      2. Tap Normal Left.

      3. Tap Impaired Right.

      4. Tap Vision.

      5. Tap Impaired.

      6. Tap Glasses.

      7. Tap Far-sighted.

      8. Tap Next Page to move to the next form. Next Page appears as

         text (not as a button) in the upper-right corner of the screen.

 - The sixth form is a diagnosis screen. Use the scroll bars to scroll

   through the potential diagnoses (some of them are rather humorous),

   and select the most appropriate one. This is the last form, so tap

   the Exit button (represented by an open door) at the bottom of the

   screen to close the application.

 - The seventh form is brought up every time you tap the open door

   icon. The menus allow you to save your work, view the different

   screens that you have entered, or exit the application.

You move from form to form using the Next Page or Previous Page

buttons at the bottom of the screen. You can close the application or

skip pages at any point by tapping the half-open door icon at the

bottom of the screen.

HEALTH was built and tested under Microsoft(R) Windows(TM) version 3.1

and Visual Basic version 1.0. The program requires PENWIN.DLL, which

can be found in both Microsoft Windows for Pen Computing and the

Microsoft Windows version 3.1 Software Development Kit (SDK).

Download HEALTH.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HEALTH.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HEALTH.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HEALTH.EXE

Additional reference words: 3.10 softlib HEALTH.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenMisc


SAMPLE: INSURE2 Visual Basic Pen Insurance Application

Article ID: Q97221

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

INSURE2 is a Visual Basic pen program that displays an insurance policy

application for insurance agents to fill out.

INSURE2 demonstrates the functionality of Visual Basic controls for

Microsoft(R) Windows(TM) for Pen Computing. It uses bedit fields,

hedit fields (with DelayRecog on and off), and an array of "point-and-

shoot" fields (check boxes, option buttons, and so on). INSURE2 is very

flexible; you can go back and forth between edit screens to update

information.

On the main form, the Current Occupation input area is ink, so you can

write in cursive. To access the list boxes, just tap the associated

buttons.

The Load and Save Form buttons are not functional, but tapping these

does not cause any error messages. Click the action buttons at the

bottom of each form to move back and forth between forms. To exit the

application, tap the Report button and select the Exit application

button at the bottom of the screen.

INSURE2 was built and tested under Microsoft Windows version 3.1 and

Visual Basic version 1.0. The program requires PENWIN.DLL, which can

be found in both Microsoft Windows for Pen Computing and the Microsoft

Windows version 3.1 Software Development Kit (SDK).

Download INSURE2.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for INSURE2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download INSURE2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get INSURE2.EXE

Additional reference words: 1.00 softlib INSURE2.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenVB


SAMPLE: LOANAPP Sample Pen Loan Application

Article ID: Q97222

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

LOANAPP is a Microsoft(R) Windows(TM) for Pen Computing application

that was developed using Visual Basic with Professional Toolkit.

LOANAPP lets you fill out a loan application using bedit fields, check

boxes, and hedit fields.

To input information, double-click a field to bring up that section's

input screen and write in the information. To change or reenter

information in an input field, double-click the input field. To move

from screen to screen, tap the buttons at the top of the screen.

Select Save from the File menu to save data. Select Load from the File

menu to load in a demo file that you might have created earlier.

There is some really good editing going on in LOANAPP. For example, no

matter where you write in the bedit fields, your entry appears left

justified in the final form. The application converts the State field

entry to uppercase, regardless of how you entered it.

LOANAPP was developed for the mobile environment, which requires large

input fields and a clear indication of where the user should enter

information. In LOANAPP, input fields appear on separate screens,

background colors are blue/black, and input fields are white.

On the last screen, double-click the Date field at the bottom of the

screen to display the current date. LOANAPP reads the time setting

from your pentop. Use the buttons at the top of each form to delete

either all fields in the current screen or all fields in all screens.

Double-click the Erase Signature buttons to clear Signature boxes. To

exit the application, choose Exit from the File menu.

LOANAPP was built and tested under Microsoft Windows version 3.1 and

Visual Basic version 1.0. The program requires PENWIN.DLL, which can

be found in both Microsoft Windows for Pen Computing and the Microsoft

Windows version 3.1 Software Development Kit (SDK).

Download LOANAPP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LOANAPP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LOANAPP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LOANAPP.EXE

Additional reference words: 1.00 softlib LOANAPP.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenVB


SAMPLE: RECEIPT Order Application for Pen Windows

Article ID: Q97223

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

RECEIPT is a Microsoft(R) Windows(TM) for Pen Computing application

that was developed using Visual Basic with Professional Toolkit.

RECEIPT lets you fill out an order for Microsoft products, do a credit

check, and pay for the product.

RECEIPT is a fun application that the Visual Basic group at Microsoft

put together for the Windows version 3.1 announcement. It mirrors the

process Microsoft uses to take product orders and highlights the

importance of connectivity.

You must follow the demo outline below to see the complete

functionality of the application:

1. Write "Mike Smith" in the Name field. If you get a recognition

   error, write over the unrecognized character.

2. Tap the Look-Up button in the upper-right corner of the screen.

3. Tap the product list box and select a few products. Tap again to

   add products to the table and order totals below.

4. Tap the Place Order button in the upper-right corner of the screen.

5. Erase "Mike Smith" using the scratch out gesture, and write in a

   new name. If you get a recognition error, write over the character

   that was misrecognized.

6. Tap the Check Credit button in the lower part of the screen.

7. Tap the Bill Me Later option button and sign for the order.

8.  Tap the Place Order button.

9. Close the application by double-tapping the Windows icon in the

   right half of the screen.

RECEIPT was built and tested under Microsoft Windows version 3.1 and

Visual Basic version 1.0. The program requires PENWIN.DLL, which can

be found in both Microsoft Windows for Pen Computing and the Microsoft

Windows version 3.1 Software Development Kit (SDK).

Download RECEIPT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RECEIPT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RECEIPT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RECEIPT.EXE

Additional reference words: 1.00 softlib RECEIPT.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenVB


SAMPLE: SALEANAL Forcast Tracking Application for Pen Windows

Article ID: Q97224

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SALEANAL is a Microsoft(R) Windows(TM) for Pen Computing application

that was developed using Visual Basic with Professional Toolkit. The

application implements a salesperson's performance sheet and includes

built-in calculations, note areas to capture ink, and links to

Microsoft Excel for charting capabilities.

SALEANAL consists of three main forms:

 - The first form contains the date, sales representative name, and

   territory fields, which are used as indexes into a database. The

   available sales representatives and territories are stored in a

   drop-down list box. You can add new names and territories to this

   list.

 - If SALEANAL finds information in the database pertaining to the

   selected date, sales representative, and territory, it displays a

   Revenue and Expense Report form with this information. If it does

   not find any information, it displays the forecast for the current

   month and for the next month, but does not show actual figures. You

   can also enter notes or view a Year-to-Date Profit chart in

   Microsoft Excel.

 - The third form displays information on days worked, calls taken, new

   accounts gained, and total accounts gained. You can also enter

   notes or view a Year-to-Date Profit chart in Microsoft Excel. This

   chart shows how an account might leverage the 5,000+ Windows-based

   applications to produce a chart that highlights a sales

   representative's performance.

If Microsoft Excel is not installed on your machine, tap the chart

icon in the third screen. This button launches Microsoft Excel and

automatically creates a chart.

You can access the Notes screen from the second or third form. This

screen lets you enter notes for the form. Notes are maintained while

you view or modify the information for a particular date, sales

representative, and territory, but are lost when you return to the

first screen or exit the application.

SALEANAL was built and tested under Microsoft Windows version 3.1 and

Visual Basic version 1.0. The program requires PENWIN.DLL, which can

be found in both Microsoft Windows for Pen Computing and the Microsoft

Windows version 3.1 Software Development Kit (SDK).

Download SALEANAL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SALEANAL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SALEANAL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SALEANAL.EXE

Additional reference words: 1.00 softlib SALEANAL.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenVB


SAMPLE: Floating-Point Samples for Windows

Article ID: Q97265

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

WinFloat: Floating-Point Samples for Windows(TM)

WinFloat consists of five programs and libraries that provide sample code

and tools to explore the floating-point mechanisms of Microsoft(R) Windows:

 - FLOATAPP.EXE: Windows-based application used as a shell for testing

   application and dynamic-link library (DLL) floating-point issues.

   This application tests floating-point speed, generates exceptions,

   installs signal handler, masks and unmasks exceptions, and

   communicates with WIN87EM.DLL. Some capabilities depend on the math

   package chosen and/or the presence of a math coprocessor.

 - FLOATDLL.DLL: Floating-point Windows DLL. FLOATDLL is a subset of

   FLOATAPP, to which it dynamically links. FLOATDLL can generate and

   handle floating-point exceptions, and can be configured to install

   and maintain its own signal handler or use the default (or

   application) handler.

 - FLOATDOS.EXE: Floating-point MS-DOS(R) application. FLOATDOS is a

   subset of FLOATAPP that runs outside of Windows (or in a "DOS

   box"), thus allowing you to compare an MS-DOS application with a

   Windows-based application for exception handling and (most

   importantly) calculation speed.

 - HIDE87.COM:  MS-DOS terminate-and-stay-resident (TSR) program that

   hides the 80x87 from Windows-based applications. HIDE87 must be

   installed before you start Windows so you can trick Windows into

   thinking there's no math coprocessor.

 - SHOW87.EXE:  MS-DOS control program that disables the HIDE87 TSR.

   SHOW87 provides a way to turn off HIDE87 without rebooting the

   machine. As with HIDE87, SHOW87 must be executed before you start

   Windows so it can detect the math coprocessor.

See the sample code and the "Floating Point in Windows" technical

article for descriptions of these programs, their coding techniques,

and the Windows floating point architecture. For information on

building these programs and discussions of C version 6.0 versus C/C++

version 7.0 and emulator versus alternate math packages, see the make

file. Note that these sample have major limitations if compiled with C

6.0.

WINFLOAT was built and tested under Microsoft Windows version 3.1

using Microsoft Macro Assembler version 6.0 and Microsoft C/C++

version 7.0.

Download WINFLOAT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINFLOAT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINFLOAT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WINFLOAT.EXE

Additional reference words: 3.10 softlib WINFLOAT.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrFltPt


SAMPLE: TOOLBAR Demonstrates Creating a Toolbar

Article ID: Q97303

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

TOOLBAR builds a toolbar similar to the Microsoft(R) Windows(TM) for

Workgroups toolbar, which was implemented through the COMMCTRL

dynamic-link library (DLL).

A toolbar consists of a row of small, graphical buttons usually placed

across the top of a window. It gives the user a fast and convenient

alternative to using the window's menu to perform operations. The menu

provides a more easily understood way to activate a function and

includes a keyboard interface to the function. A toolbar, on the other

hand, gives the experienced user a shortcut to operations, and thus

improves the usability of an application.

TOOLBAR is a companion sample application for the "Creating a Toolbar"

technical article on the Microsoft Developer Network CD.

TOOLBAR was built and tested under Microsoft Windows version 3.1. The

sample also builds and runs under Microsoft C/C++ version 7.0 and

Visual C++ version 1.0.

Download TOOLBAR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TOOLBAR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TOOLBAR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TOOLBAR.EXE

Additional reference words: 3.10 softlib TOOLBAR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Launching One Application for Windows from Another

Article ID: Q97331

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

APPEXEC is a technical note in the Microsoft Software Library that

discusses launching Windows-based applications from other applications for

Windows. APPEXEC is a Windows Help file.

Download APPEXEC.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for APPEXEC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download APPEXEC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get APPEXEC.EXE

MORE INFORMATION

================

Abstract

--------

An application for Microsoft Windows often needs to be launched from

another Windows-based application. In addition to starting a second

application, sometimes the primary application needs to know when the

second application terminates.

This technical article discusses the following points:

 - Several ways to start applications

 - An approach to finding applications not located on the current

   Windows search path

 - A method for detecting whether an application is still running

 - Using the same Windows-based techniques for starting applications

   for MS-DOS

APPEXEC, the sample application provided with this article, contains

code that solves the problems involved in finding and starting one

Windows-based application from another, as well as determining later

whether that application is still running.

Additional reference words: 3.10 softlib APPEXEC.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrTsksIns


SAMPLE: FAULTS.RTF - Technical Article

Article ID: Q97337

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Bulletproof Functions with ToolHelper

Kraig Brockschmidt

Systems Developer Relations

Created: March 30, 1992

For Microsoft OnLine customers, FAULTS.RTF is available in the

Microsoft Software Library as 10X15.ZIP and can be found by searching on

the word FAULTS.RTF, the Q number of this article, or S13950. For

CompuServe Customers, FAULTS.RTF can be downloaded from the file

10-15.ZIP in library section number 10 of the MSDNLIB forum.

FAULTS.RTF was archived using the PKware file-compression utility.

Additional reference words: 3.10 softlib

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: GetGlyphOutline() Function Demonstration

Article ID: Q97340

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

Advanced TrueType: GetGlyphOutline

Ron Gery

Microsoft Developer Network Technology Group

Abstract

This article presents a usable explanation of the GetGlyphOutline()

function. Rather than being a complete guide, it is intended to complement

and complete the definition found in the Microsoft Windows version 3.1

Software Development Kit (SDK) Programmer's Reference, Volume 2: Functions.

To follow the discussion, the reader should be familiar with the

information on GetGlyphOutline() in the SDK and the basic theory of the

TrueType font engine. A sample application, GLYPH, is included on the

Microsoft Developer Network CD to illustrate the basic concepts and

mechanisms in this article.

Download GLYPH.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GLYPH.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GLYPH.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get GLYPH.EXE

Additional reference words: 3.10 softlib

KBCategory: kbprg kbfile

KBSubcategory: GdiFnt


SAMPLE: MINMAX Demonstrates the WM_GETMINMAXINFO Message

Article ID: Q97348

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Kyle Marsh

Microsoft Developer Network Technology Group

The Microsoft Windows graphical environment provides the

WM_GETMINMAXINFO message for applications to control the maximized

size and position, the maximum tracking size, and the minimum tracking

size of a window.

MINMAX demonstrates the WM_GETMINMAXINFO message that allows

applications to control the maximized size and position, the maximum

tracking size, and the minimum tracking size of a window. For more

information, see the "WM_GETMINMAXINFO" technical article.

Download MINMAX.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MINMAX.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MINMAX.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MINMAX.EXE

Additional reference words: 3.10 softlib MINMAX.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Palette Utilization Demonstration

Article ID: Q97352

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

This article discusses basic palette awareness---what it takes for an

application to use palettes correctly in the Microsoft Windows graphical

environment---by covering these areas:

 - Responding to palette-related messages

 - Managing palette-based bitmaps

 - Managing multiple palettes in one application

 - Using the Clipboard with palettes

MORE INFORMATION

================

The reader should be familiar with basic palette use for painting

operations. This article is not about the Palette Manager, and the

level of detail is limited to the very basics of the palette managing

process. A sample application, MULTIPAL, is included on the Microsoft

Developer Network CD to illustrate the use of multiple palettes in a

single application.

MULTIPAL is also included with the PALAWARE technical article located in

the Microsoft Software Library.

Download PALAWARE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PALAWARE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PALAWARE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PALAWARE.EXE

MULTIPAL is a multiple document interface (MDI) extension to the DIBIT

sample program that accompanies the "Using DIBs with Palettes"

technical article. MULTIPAL allows you to display multiple DIBs with

multiple palettes and handles palette messaging from both the system

perspective and the application perspective. The MDI skeleton is taken

from the BLANDMDI program that is included in the Microsoft(R)

Windows(TM) version 3.1 Software Development Kit (SDK). MULTIPAL

achieves device independence by using palettes at all times,

regardless of the type of device being used.

To see the application in action, open several color-intensive 8-bit

device-independent bitmaps (DIBs) at the same time and change the

active DIB window. To see the application's interaction with the rest

of the system, run another application that uses palettes (another

instance of MULTIPAL will do).

Additional reference words: 3.10 softlib MULTIPAL.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPal


SAMPLE: Window Hierarchy and Styles

Article ID: Q97360

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Window Hierarchy and Styles

Kyle Marsh

Microsoft Developer Network Technology Group

Created: April 7, 1992

This article describes the desktop, top-level, and child windows provided

in the Microsoft Windows graphical environment and their hierarchical

relationships. It explains how an application can use Windows-based

functions to navigate the window structure and to control the style and

appearance of a window on the desktop.

Download STYLES.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for STYLES.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download STYLES.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get STYLES.EXE

Additional reference words: 3.10 softlib STYLES.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: TRANSBLT Demonstrates Bitmaps with Transparency

Article ID: Q97365

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Bitmaps with Transparency

Ron Gery

Microsoft Developer Network Technology Group

ABSTRACT

========

This article discusses several methods for performing transparency and

masking effects with bitmaps in the Microsoft Windows graphical

environment, both through simulations and by using special driver

functionality. Included is a small sample application, TRANSBLT, that

demonstrates most of the techniques discussed in this article.

TRANSBLT performs transparency and masking effects on bitmaps.

Download TRANSBLT.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TRANSBLT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TRANSBLT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TRANSBLT.EXE

Additional reference words: 3.10 softlib TRANSBLT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: A Virtual List Box Implementation

Article ID: Q97371

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

A Virtual List Box Implementation with VLIST

Kyle Marsh

Microsoft Developer Network Technology Group

Created: September 2, 1992

Revised: January 26, 1993

The standard list box control in Microsoft Windows can contain a

limited number of items. Applications may need to implement list boxes

that exceed this limitation. This article introduces a custom control

called VLIST, which is a virtual list box capable of displaying

millions of items. Part 1 of the article provides instructions for

using the VLIST virtual list box, and documents the styles and

messages that VLIST supports. Part 2 describes how VLIST was

implemented, and discusses the problems encountered and decisions made

during the implementation; readers who would like to modify VLIST or

implement their own virtual list box may find this section

interesting. For a working example of VLIST, see the Microsoft

Developer Network CD---the topic listing in the Index window was

implemented with VLIST.

VLIST implements a single-selection, single-column virtual list box capable

of displaying millions of items. The standard list box control in Microsoft

Windows can contain a limited number of items. VLIST shows how to implement

list boxes that exceed this limitation.

Download VLB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for VLB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download VLB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get VLB.EXE

Additional reference words: 3.10 softlib VLIST.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Hierarchical List in Owner-Draw List Box

Article ID: Q97396

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Displaying a Hierarchy in a List Box

Kyle Marsh

Microsoft Developer Network Technology Group

Created: December 22, 1992

This article explains how to create a hierarchical list box that

includes icon bitmaps and connecting lines. It describes what an

application must do to display the hierarchy and discusses some helper

functions I developed specifically to make the process easier for the

application developer. HIERLIST, the sample application included with

this article, implements a hierarchical list box with these helper

functions.

HIERLIST implements a hierarchical list box that includes icon bitmaps

and connecting lines. It demonstrates what an application must do to

display the hierarchy and includes some helper functions developed to

make the process easier for the application developer.

Download HIERLIST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for HIERLIST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download HIERLIST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get HIERLIST.EXE

Additional reference words: 3.10 softlib HIERLIST.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: FONTUTIL.RTF - Technical Article

Article ID: Q97397

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

----------------------------------------------------------------------

Font Utilities---Some Handy-Dandy Font-Handling Functions

Charlie Kindel, Microsoft Premier Support Services

Kyle Marsh, Microsoft Developer Network Technology Group

Created: January 10, 1993

Handling fonts in Microsoft Windows-based applications can involve a

lot of grunt work. For example, essential tasks such as creating

fonts, retrieving point sizes, and calculating text metrics can take

up a lot of the developer's time and effort. This article describes

some useful font-handling functions that take care of most of this

tedious work, thus making it easier to create and manipulate fonts in

Windows.

The FONTUTIL sample application demonstrates most of the font-handling

functions discussed in this technical article. FONTUTIL contains useful

font-handling routines that make it easier for an application to create and

manipulate fonts in Microsoft Windows by taking care of most of the tedious

work.

The font utilities are primarily for applications that need the

relatively simplistic font model presented in the ChooseFont common

dialog box. ChooseFont() deals with fonts using four primary variables:

typeface name, typeface style, point size, and effects. ChooseFont

also allows for color selection, but the font-handling functions do

not currently support this feature.

The font-handling functions allow an application to create and

interrogate fonts in a manner that is consistent with the ChooseFont

model. For example, you can create a font by using the

ReallyCreateFont() function and specifying the typeface name, typeface

style, and point size; you can retrieve the typeface style of a font

by using the GetTextStyle() function; and so on.

The font utility functions support Microsoft Windows versions 3.0 and

3.1, and Windows NT version 3.1. You can include the functions

either in an application or in a dynamic-link library (DLL).

Download FONTUTIL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FONTUTIL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FONTUTIL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FONTUTIL.EXE

Additional reference words: 3.10 softlib

KBCategory: kbprg kbfile

KBSubcategory: GdiFnt


SAMPLE: Implementing Owner-Draw Combo Boxes

Article ID: Q97399

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Rescue of the COMMDLG Bitmaps

Kraig Brockschmidt

Software Design Engineer, Microsoft Windows Developer Relations

Created: January 13, 1993

This article discusses the implementation of an owner-drawn combo box

and list box that use the drive and folder icons from the Microsoft

Windows version 3.1 Software Development Kit (SDK).

DDLIST utilizes the unused bitmaps that are included in the Microsoft

Windows version 3.1 Software Development Kit (SDK) SAMPLES\COMMDLG

directory for the File Open and File Save dialog boxes. DDLIST implements

the drives combo box and the directory list box as an interrelated pair in

a dialog box, fully utilizing the drive type and folder icons available

with the Windows SDK. All the bitmaps are loaded separately and maintained

in two global HBITMAP arrays. The code to draw the combo box and list box

items references these arrays.

Download DDLIST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DDLIST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DDLIST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DDLIST.EXE

Additional reference words: 3.10 softlib DDLIST.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Measuring System Timings by Using Printer Port

Article ID: Q97402

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

Use Your Printer Port to Measure System Timings

Herman Rodent

Microsoft Developer Network Technology Group

Created: January 4, 1993

If you need to measure interrupt latency, interrupt-service-routine

execution time, or procedure call overhead---or if you just plain want

to know why your application is so slow---here's an article that

describes a simple way to use a printer port and an oscilloscope to do

timing measurements.

If you don't know what an oscilloscope is, you can either stop reading

now and return to struggling with your code, or look forward to

renting a new toy to play with.

PPDEBUG.ASM is an assembly language code module that provides

C-callable services to set and clear the bits on the printer port.

PPDBG.INC is an assembly language include file that provides macros to

assembly language code modules.

These modules demonstrate the concepts discussed in the "Use Your

Printer Port to Measure System Timings" technical article on the

Microsoft(R) Developer Network CD.

Download PPDEBUG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PPDEBUG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PPDEBUG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PPDEBUG.EXE

Additional reference words: 3.10 softlib PPDEBUG.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrSys


SAMPLE: DDEEXEC Demonstrates DDE Execute Strings

Article ID: Q97408

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

DDE Execute Strings

Herman Rodent

Microsoft Developer Network Technology Group

Created: November 16, 1992

The dynamic data exchange (DDE) protocol includes a feature designed

to allow a DDE client application to send commands to a DDE server.

The syntax of these execute requests and the way they should be

handled by servers is not well documented and, consequently, varies

slightly with different implementations.

The current DDE protocol has no provision for returning result

information from an execute request, so a client application can only

tell that the request failed, not why it failed.

This article proposes a consistent way to handle DDE execute command

requests and a mechanism that allows result information to be

returned. This article covers the following points:

 - DDE execute command syntax

 - Special characters in command arguments

 - Unicode considerations for Microsoft Windows NT

 - The returning of result information

DDEEXEC is a dynamic data exchange (DDE) server that supports an

Execute command set. The commands allow DDE client applications to

draw pictures in the main window of the server. The following sample

client applications use the DDEExec server and are included with this

application:

 - EXEC is a Visual Basic(TM) version 2.0 application that allows any

   Execute command to be sent to a given topic of a DDE server. This

   sample client application tests the basic command set of a DDE

   server and ensures that the server reports command errors

   correctly.

 - BUNNY is a Visual Basic 2.0 application that uses the server to draw

   a picture of a bunny rabbit.

 - WBUNNY.DOC is a Word for Windows(TM) document based on the

   WBUNNY.DOT template that uses Word's embedded Basic language to

   draw yet another bunny picture.

 - XLART.XLM is a sample Microsoft Excel macro sheet that shows how you

   can use Microsoft Excel as a DDE client to draw fascinatingly

   complex pictures.

Download DDEEXEC.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DDEEXEC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DDEEXEC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DDEEXEC.EXE

Additional reference words: 3.10 softlib DDEEXEC.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: DDESERV Demonstrates a Basic DDE Server

Article ID: Q97409

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Quick and Easy DDE Server

Herman (Mr. DDE) Rodent

Microsoft Developer Network Technology Group

Adding dynamic data exchange (DDE) server support to an application

has never been easier. This article describes a code module you can

include in your own application that makes adding DDE server support

trivial. The code module makes use of the dynamic data exchange

management library (DDEML) to implement the DDE protocol and provides

the following features:

 - Full System topic support

 - An application programming interface (API) to dynamically add and remove

   topics and topic/item pairs

 - An API to dynamically add and remove DDE execute commands to a topic

 - Automatic tracking of conversations

 - Built-in execute command parser

 - Partial support for the Execute Control 1 protocol, which allows a

   result string to be returned in response to a DDE execute command

   request

This article requires considerable familiarity with DDE concepts---it's not

a good place to start learning about DDE. Please refer to the Microsoft

Windows version 3.1 Software Development Kit (SDK) Programmer's Reference,

Volume 1: Overview, Part 2: Extension Libraries for a general introduction

to DDE and DDEML. The following articles on the Microsoft Developer Network

CD (Technical Articles, Windows Articles, OLE and DDE Articles) provide

more detail on various DDE topics:

 - "DDE Execute Strings"

 - "DDE Hot Links"

 - "Performing DDE from a Dynamic-Link Library"

 - "Raw DDE"

 - "Supporting the Clipboard, DDE, and OLE in Applications"

 - "Supporting the DDE System Topic"

DDESERV shows how you can easily create a dynamic data exchange (DDE)

server that supports the System topic and an Execute command set. You

can build the server by using the STDDDE.C module included in the

sample.

Download DDESERV.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DDESERV.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DDESERV.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DDESERV.EXE

Additional reference words: 3.10 softlib DDESERV.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Global Heap Functions

Article ID: Q97940

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SHOWMEM is a sample application that allows the user to allocate, free, and

manipulate memory from the global heap. Different "what if" scenarios can

be demonstrated without writing and rewriting code. Information about

global heap objects is displayed using the GlobalEntryHandle() and

ModuleFindHandle() TOOLHELP.DLL functions. Additional information about how

to use the global heap functions is provided, as well as a collection of

related Microsoft Knowledge Base articles in help-file format.

Download SHOWMEM.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SHOWMEM.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SHOWMEM.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SHOWMEM.EXE

Additional reference words: 3.10 softlib SHOWMEM.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrMm


SAMPLE: PATPOLY Demos Polygon Filled with Dithered Color

Article ID: Q98619

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

PATPOLY is a file in the Microsoft Software Library that demonstrates how

to draw a polygon so that the entire polygon, including the border, can be

filled with a dithered color in an application for the Microsoft Windows

environment.

Download PATPOLY.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PATPOLY.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PATPOLY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PATPOLY.EXE

MORE INFORMATION

================

It is not possible to fill a polygon and its border with a dithered color

using just a call to the Windows Polygon() application programming

interface (API), because of problems producing the border with a dithered

color. Using a NULL pen doesn't work because not all of the interior and

border will be filled. Pens with a width of 1 can have only solid colors,

so they don't work. Wider pens can have a dithered color, but because the

pen is centered on the polygon border as defined by the vertex points, the

resulting polygon is larger than defined by the vertices. Also, the

PS_INSIDEFRAME pen style does not have any affect when used with Polygon().

To accomplish the desired result, the PatPolygon() function first creates a

monochrome mask of the polygon in a memory device context (DC), and then

blits the mask transparently to the screen using a pattern brush containing

the dithered color.

This sample also demonstrates how to load a device-independent bitmap

(DIB) resource and create a DIB pattern brush with it.

Additional reference words: 3.00 3.10 softlib PATPOLY.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiDrw


SAMPLE: Annotating and Printing Text and Ink Together

Article ID: Q98626

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Software Library, there is a sample called AnnoPrnt.

This is a Windows for Pen Computing sample that demonstrates how to

annotate a text file with ink, and then print out the resulting

annotated text to any printer.

Download ANNOPRNT.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for ANNOPRNT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ANNOPRNT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ANNOPRNT.EXE

MORE INFORMATION

================

Using the AnnoPrnt sample as a starting point, developers can view one

method to output annotated text. Certain Windows for Pen Computing

application programming interfaces (APIs) are more suited to output to

printer devices. This is the case here with using DrawPenData rather

than RedisplayPenData. RedisplayPenData is more device-dependent on the

video driver and not meant to be used in printer calls.

The AnnoPrnt sample also shows how to output different colors of ink

so that developers can view the results of the color mapping on their

respective printer; some colors are mapped such that they don't show

up on a printer.

Another method of printing involves printing the entire image (the

annotated text file) as a device-independent bitmap (DIB), thus

allowing the driver, not GDI, to do the color mapping. Drivers

typically do a better mapping to grayscale, and therefore if color is

important, using DIBs is an alternative. The WINCAP sample in the

Software Library demonstrates outputting DIBs to printers.

The AnnoPrnt sample was carefully checked for possible printing

problems; however, because so much is dependent on printer drivers,

future errors are possible. If you experience problems with this

sample, please contact the Windows for Pen Computing support personnel

on CompuServe, in the WINEXT forum, Section 8 (the Pen section).

Additional reference words: 1.00 softlib ANNOPRNT.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenInk


SAMPLE: Advanced ALC_ Sample and ShowKeyboard() Sample

Article ID: Q98627

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

In the Microsoft Software Library, there is a sample called AlcKey.

This is a Windows for Pen Computing sample that demonstrates how to

use the ALC values (defined in Windows for Pen Computing) to set how

an hedit (or bedit) control filters its input.

Download ALCKEY.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ALCKEY.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ALCKEY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ALCKEY.EXE

MORE INFORMATION

================

ALC values can be set to define what values are recognized in a pen

edit control (either hedit or bedit). For example, by setting

ALC_NUMERIC, only numeric values are recognized in that particular

control. Using ALC values allows developers greater freedom to

customize how their application responds to ink. By defining a small

subset of only the types of values wanted in an edit control,

recognition of those values increases.

The AlcKey sample has two edit controls, hedit and bedit. By selecting

the ALC flags desired via the ALC dialog box, the hedit control is set

to those values. The bedit control is not altered, allowing the

developer to view the difference between the settings of the two

controls.

The AlcKey sample also demonstrates the use of the ShowKeyboard()

application programming interface (API), including the recommended way

of interfacing to the virtual keyboard via a "keyboard" button; which

is OwnerDraw. Note that the virtual keyboard always stays on top, but

never has the focus. The output of the keyboard is directed to the

last control that had the focus. Note also that the virtual keyboard

in Windows for Pen Computing version 1.0 is not affected by the

filtering effects of the ALC values. Only recognized ink is affected;

the keyboard does not involve inking, so it bypasses this step.

Additional reference words: 1.00 softlib ALCKEY.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenKeyboard


SAMPLE: VIEW Demonstrates Drawing Ink at a Slower Rate

Article ID: Q98681

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

The VIEW sample is a Windows for Pen Computing sample that demonstrates how

to:

 - Display ink via RedisplayPenData()

 - Display the "best guess" in text from the Recognizer

 - Use TrueType fonts to mimic the same height of the raw ink text

 - Display how to parse through the individual ink data points and do

   a "slow draw" of the ink, much like the Trainer application does.

Download VIEW.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for VIEW.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download VIEW.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get VIEW.EXE

MORE INFORMATION

================

View allows developers to experience how ink display is done, and

provides one conversion algorithm that can be used to convert the raw

ink into recognized values [see SYV, SYG, SYE, and SYC in the

Microsoft Windows for Pen Computing "Programmer's Reference" in the

Windows version 3.1 Software Development Kit (SDK) for more

information on recognition results.]

These values can then be converted and displayed as text on a device

context (DC) in a TrueType font such that a close approximation of the

raw ink string height can be mimicked by the font string itself.

Finally, the View sample demonstrates through the use of a timer

callback function, how to walk through the individual stroke points

and draw them one by one. With a timer running, it is possible to slow

down the speed at which the ink is redrawn, and thus to see

approximately how the ink was drawn by the user.

This is similar to how the Trainer application (available in the

Windows for Pen Computing environment) does its slow drawing to

demonstrate inking techniques.

View was built and tested under Microsoft Windows version 3.1. The

program requires PENWIN.DLL, which can be found in both Microsoft

Windows for Pen Computing and the Microsoft Windows version 3.1 SDK.

View also requires the TrueType Arial font.

Additional reference words: 1.0 softlib VIEW.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenInk


SAMPLE: Simple Training Techniques for a Recognizer

Article ID: Q99797

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows for Pen Computing version 1.0

----------------------------------------------------------------------

SUMMARY

=======

The following information concerns the Microsoft Windows for Pen

Computing sample Training Emulator, version 1 (TrainInk).

There is a sample called TRAINEM in the Microsoft Software Library.

This Windows for Pen Computing sample demonstrates how to do simple

training on a trainable handwriting recognizer. The sample utilizes

the TrainInk application programming interface (API) to do the

training.

Download TRAINEM.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for TRAINEM.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TRAINEM.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TRAINEM.EXE

MORE INFORMATION

================

TRAINEM is a Windows for Pen Computing version 1.0 sample, which can

be run on any Windows version 3.1 or Windows for Workgroups machine

that has the Pen Extensions installed [from the Microsoft Windows 3.1

Software Development Kit (SDK) or Visual C++ Development Kit.]

On a system that is running only the Pen Extensions and not the full

Windows for Pen Computing environment, the virtual keyboard executable

may not be present (SKB.EXE on U.S. systems) such that the

ShowKeyboard call cannot bring up the virtual keyboard. In this case,

when the Keyboard button is pressed, a dialog box will be displayed

informing the user that the virtual keyboard could not be started.

TRAINEM demonstrates one of the training APIs used in training

handwriting in a recognizer. The TrainInk API is the simpler of the

two training APIs available; however, using it requires knowledge of

recognizers and what they are capable of doing. Therefore, TRAINEM

also demonstrates querying a recognizer to determine whether it is

capable of being trained; if so, the sample demonstrates the

limitations of that training.

TRAINEM also demonstrates one method of capturing ink for training,

and displays an interface that a user can use to view that ink and

train it to the correct value. Note that during this process, ink can

be captured and saved from an hedit or bedit control, and textual

information can be retrieved with ordinary window messages.

As written, TRAINEM requires the Microsoft default recognizer, also

known as the Roman recognizer, MARS. Note that the ConfigRecognizer

call is resident in the recognizer code itself and must be imported

explicitly in the .DEF file. In the more general case, not dealt with

in this sample, an application could install the recognizer at run

time or query for the current recognizer and obtain a pointer to the

needed function. This sample uses the more direct and easier method,

though not necessarily the most robust method.

The sample also requires that some action be taken after a recognition

session has taken place in the main hedit control on the main window.

The user must choose either the Reset Hedit button or the Train button

before further recognition sessions are allowed in the control. The

control is disabled until training has taken place or until the

control is reset.

This method was used to avoid losing track of the correct ink to train

in the hedit control. More sophisticated training programs might

explore algorithms that allow for tracking multiple recognition

sessions, and bring up the appropriate result and original ink on

request for training. This sample is a simple demonstration of the

basics required for training a recognizer; more sophisticated

algorithms for handling multiple recognition sessions are beyond its

scope.

Additional reference words: 1.00 softlib TRAINEM.EXE

KBCategory: kbprg kbfile

KBSubcategory: WpenTrain


SAMPLE: Customizing the MDI Window Menu

Article ID: Q99803

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The MDIWINMN sample in the Microsoft Software Library demonstrates how to

customize the Window menu of a multiple document interface (MDI) frame

window. MDIWINMN shows how to limit the number of listed MDI children in

the Window menu to any number and how to bring up a customized dialog box

when the More Windows menu item is selected. This sample also shows how to

list all the MDI children in the Window menu without using a More Windows

menu item.

Download MDIWINMN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S14184.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MDIWINMN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MDIWINMN.EXE

MORE INFORMATION

================

To compile, type NMAKE to build the sample; this sample limits the number

of MDI child windows listed in the Window menu and brings up the customized

dialog box when the More Windows menu item is selected. Type NMAKE

MENU=NOLIMIT to build the sample that lists all the the MDI children in the

Window menu without using a More Windows menu item.

The following code changes must be made in the window procedure of the

MDI frame window to customize the Window menu:

1. Specify NULL as the Window menu handle when creating the MDI client,

   because the application handles all the processing of the Window

   menu:

      CLIENTCREATESTRUCT ccs;

      ccs.hWindowMenu  = NULL;

      ccs.idFirstChild = IDM_FIRSTCHILD;

2. Update the Window menu using ChangeWindowMenu() when the frame window

   receives WM_INITMENUPOPUP. ChangeWindowMenu() is implemented in the

   sample code:

     case WM_INITMENUPOPUP:

          if ((HMENU)wParam == hMenuWindow)

             ChangeWindowMenu(hMenuWindow);

          break;

3. Call ProcessWindowMenu() in the default processing of WM_COMMAND

   received by the frame window. ProcessWindowMenu() is implemented in the

   sample code:

     case WM_COMMAND:

      {

          switch (wParam)

          {

              :

              :

           default:

              if (ProcessWindowMenu(wParam))

                    return 0L;

              else return DefFrameProc(hwnd, g_hwndMDIClient,

                                      msg, wParam, lParam);

           }

      }

ChangeWindowMenu() removes the old listing of MDI children from the Window

menu. It then enumerates the MDI child windows and adds their names to the

Window menu so the Window menu reflects the current state when shown.

ProcessWindowMenu() processes WM_COMMAND messages that result from menu

selections of MDI children in the Window menu. It also brings up a

customized dialog box when the More Windows menu item is selected.

Additional reference words: 3.00 3.10 softlib MDIWINMN.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMdi


SAMPLE: Shell DDE Using DDEML

Article ID: Q99807

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

The Windows Program Manager supports a dynamic data exchange (DDE) command-

string interface that allows other applications to create, display, delete,

and reload groups; add, replace, and delete items from groups; and to close

Program Manager.

PMDDEML is a file in the Microsoft Software library that demonstrates how

to use this Program Manager DDE command-string interface using the Dynamic

Data Exchange Management Library (DDEML) introduced in Microsoft Windows

version 3.1.

Download PMDDEML.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download S14197.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PMDDEML.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PMDDEML.EXE

MORE INFORMATION

================

PMDDEML demonstrates only a small subset of the command-strings supported

by Program Manager. The commands demonstrated by PMDDEML include:

   CreateGroup

   ShowGroup (both minimize and restore)

   DeleteGroup

The other command-strings supported by Program Manager can be easily

implemented in a manner similar to those commands demonstrated by PMDDEML.

The DDEML functions demonstrated by PMDDEML include:

   DdeInitialize

   DdeUninitialize

   DdeConnect

   DdeDisconnect

   DdeCreateStringHandle

   DdeFreeStringHandle

   DdeClientTransaction

To use PMDDEML, run it and select the Shell Commands menu. Choose the

Create "Sample Group" menu item. This will create a new program group (if

one does not already exist) in Program Manager. Once the sample group is

created, the group can be minimized, restored, or deleted by selecting the

appropriate menu item in PMDDEML.

Additional reference words: 3.10 softlib PMDDEML.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDde


SAMPLE: Changing Background and Text Color of Message Box

Article ID: Q99808

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

MSGCOLOR is a file in the Microsoft Software Library that demonstrates how

to change the background and text color of a message box by subclassing the

message box.

The MSGCOLOR sample implements the ColorMessageBox() function, which

creates a message box whose background and text color can be changed. The

function subclasses the message box and processes WM_CTLCOLOR to modify the

colors. Subclassing the message box requires obtaining the window handle of

the message box. The window handle is obtained using a WH_CBT hook. The

hook is called when the message box is created, and provides access to the

window handle.

Download MSGCOLOR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MSGCOLOR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MSGCOLOR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MSGCOLOR.EXE

Additional reference words: 3.10 softlib MSGCOLOR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: Connect Net Drive--a File Manager Extension

Article ID: Q99862

SUMMARY

=======

The NETCON program sample demonstrates how to create a dynamic-link library

(DLL) that will extend the File Manager application in Microsoft Windows

versions 3.1 and later. The program sample exports a function called

FMExtensionProc(), which File Manager sends messages to during its

initialization. NETCON adds a Quick Connect menu to File Manager (in

Windows for Workgroups, NETCON adds a toolbar button and a help string to

be displayed in the status bar when the toolbar button is selected). When

the Quick Connect menu item is selected, NECON.DLL brings up a Connect

Network Drive dialog box. The program uses the following network

application programming interface (API), which must be supported by the

network that Windows is running on:

   - WNetAddConnection()

   - WNetGetConnection()

NETCON also maintains the MRU_Files section of WIN.INI in the exact manner

that Windows for Workgroups does. Unlike the Connect Network Drive dialog

box that comes with Windows for Workgroups, this dialog box does not browse

for available drives during initialization, and therefore startup time may

be significantly faster.

Download NETCON.EXE from the Microsoft Software Library (MSL) on the

following services:

 - CompuServe

      GO MSL

      Search for NETCON.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NETCON.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NETCON.EXE

MORE INFORMATION

================

To enable File Manager to use the DLL, and the following line to the

[AddOns] section of WINFILE.INI:

   Quick Net Connection = netcon.dll

Additional reference words: 3.10 softlib NETCON.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrExt


SAMPLE: Accelerators for File Manager Extensions

Article ID: Q100357

SUMMARY

=======

File Manager extensions cannot directly use accelerators because

extensions do not have their own message pump. File Manager pulls

messages on behalf of the extensions, and does not load and translate

extensions's accelerators.

Download XTENACCL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for XTENACCL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download XTENACCL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get XTENACCL.EXE

MORE INFORMATION

================

XTENACCL installs a task-specific message hook (WH_GETMESSAGE) and

calls TranslateAccelerator() on every WM_KEY and WM_KEYDOWN message.

If an appropriate accelerator is found, TranslateAccelerator() passes

a WM_COMMAND to the main window.

The main window of File Manager handles and processes the WM_COMMAND

message passed to it by TranslateAccelerator(). However, File Manager

does not know how to handle that message because wParam (containing

menu IDs) is defined by the extension. To interpret the correct value,

File Manager dynamically changes an extension's menu IDs to suit its

own needs. Therefore, XTENACCL traps the WM_COMMAND message passed by

TranslateAccelerator() and routes it to a child window of its own. The

child window in turn processes the menu command.

To intercept the WM_COMMAND message, XTENACCL is using a second

message hook that is of type WH_CALLWNDPROC. Because TranslateAccelerator()

sends a WM_COMMAND instead of posting it, this

second hook was needed.

Additional reference words: 3.10 file manager extension softlib

XTENACCL.ZIP

KBCategory: kbprg kbfile

KBSubcategory: UsrExt


SAMPLE: lstrcmpi, Accented Chars, and Sort Order in Windows

Article ID: Q100366

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

---------------------------------------------------------------------

SUMMARY

=======

This article provides supplementary information to Section 18.2.2.1

"Comparing and Sorting Strings" in the Windows version 3.1 Software

Development Kit "Programmer's Reference, Volume 1: Overview" manual and the

Windows Help International Overview section. Specifically, this article

provides information about the sort order used by the Windows lstrcmp and

lstrcmpi functions, the location of accented characters in the sort, and

how primary and secondary values, or weights, are important when sorting a

string using these functions. This includes the different behavior of these

functions when a language driver is installed compared to when Windows's

internal sort routine (English/American) is used.

List boxes that include the LBS_SORT style use lstrcmpi internally to

perform the sort. Consequently, the information in this article applies to

these list boxes also.

ALPHSORT is a sample that shows the results of these sort routines, and

contains a dialog box with two list boxes. One list box contains the

characters 32-255 and the option to display the characters in ANSI or

sorted order; the other list box includes the LBS_SORT style and contains

various strings. Changing the sort routine in use through the International

Control Panel application illustrates the effects of the different language

drivers and Windows's internal sort routine.

Download ALPHSORT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ALPHSORT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ALPHSORT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ALPHSORT.EXE

MORE INFORMATION

================

The sort order used by lstrcmp and lstrcmpi is:

1. Nonalphanumeric characters (in ASCII/ANSI order)

2. Numeric characters

3. Alphabetic characters

For performance reasons, the internal sort routine treats accented

characters as nonalphanumeric. Therefore, when the internal routine is

used, accented characters appear towards the beginning of the sort between

punctuation and numbers. In contrast, when a language driver is used,

accented characters appear near their unaccented equivalents because the

language drivers sort accented characters as alphabetic characters.

The following illustrate the differences in character order ("..."

signifies omitted characters):

ANSI Order:

   !"#...0...9:;<...ABC...XYZ[\]...abc...xyz{|}...accented characters

Internal (English/American) Sort Routine Order:

   !"#...:;<...[\]...{|}... accented characters 0...9AaBbCc...XxYyZz

Language Driver Order:

   ...!"#...:;<...[\]...{|}...0...9A accented characters aBbCc...XxYyZz...

Note that the accented characters are intermixed with their alphabetic

counterparts here.

Primary and secondary weights of characters also affect the sort order when

a language module is installed. In this case, sorting is done by primary

weight for the entire length of the string, then by length, and lastly by

secondary weight if the primary weights of all the characters and the

lengths of the strings are equal. The secondary (diacritic) weights are

important only when there is a tie in the entire string. The internal

(English/American) sort routine does not sort extended characters; as

mentioned above, they are sorted as punctuation rather than alphabetic

characters. Therefore, the internal routines produce completely different

results than the language routines in some cases.

Character weights are important with case-sensitive sorting also. For

example, using lstrcmp will produce: A < a < B < b; it will also produce:

Aaa < aaa < Aab. These examples use proper dictionary sort order, but the

second example is not necessarily obvious because if A < a, then it seems

Aab < aaa should also be true. In that case, it is said that A and a

"collide" (that is, their primary weights are the same) and a delayed

comparison must be performed if the remainders of the strings are equal.

The strings continue to be compared character by character. Because a < b,

then aaa < Aab and the comparison is complete. If the strings were equal

all the way through (such as Aaa and aaa) then A and a would collide once

again. The rest of the strings would be equal, and then the secondary

weights of A and a would be checked to determine that Aaa < aaa.

EXAMPLES WHEN A LANGUAGE DRIVER IS INSTALLED

============================================

Note: Special notation is used below to represent accented characters

due to limitations in the distribution media for this article. For

example <u umlaut> is used to represent the letter "u", which has an

umlaut over it. Likewise, <a tilde> represents the letter "a" accented

with a tilde.

Nonaccented Characters

----------------------

The sort works on a character-by-character comparison, checking

primary weights in a string. As soon as the primary (alphabetic)

weights show one string greater than the other, the comparison stops.

Therefore, sorted lists resemble the following:

   a

   aa

   abba

   ac

   add

   b

   ba

   baa

Accented Characters

-------------------

The secondary (diacritic) weights are important only when there is a tie in

the string. For example, in the following sorted list, the characters in

the first two strings have identical primary sort weights ("s", "a", "m",

"e") and the strings are the same length. Because of the tie in primary

weights and string lengths, the secondary weights are then compared. The

first difference in secondary weight ("a" versus <a tilde>) breaks the tie.

Secondary weights are also a factor when comparing strings 4 and 5 below:

1. same

2. s<a tilde>me

3. sandy

4. schon

5. sch<o umlaut>n

6. school

It is important to apply the primary weights to the whole string first, and

only use the secondary weights in a tie. The primary weights must also

carry more importance than the secondary weights as well. Otherwise, an

incorrect sort would result (such as schon less than school less than sch<o

umlaut>n). This type of weighting creates a sort that makes a distinction

between "unique," hard-coded letters of a language and mere variants of a

letter (which are only distinguished by diacritics).

Here is a sorted list using the English (International) driver:

   a

   <a grave>

   apple

   <a grave>pple

   apples

   <a grave>pples

   lu

   l<u umlaut>

   l<u umlaut>b

   lum

Here is the same list, using the internal [English (American)]

routine:

   <a grave>

   <a grave>pple

   <a grave>pples

   a

   apple

   apples

   l<u umlaut>

   l<u umlaut>b

   lu

   lum

REFERENCE

=========

For more information on the international sort, see the following:

   Canadian Standards Association Z243.4.1-1990; "Canadian Alphabetic

   Ordering Standard for Character Sets of CSA Z243.4 Standard," Alain

   LaBont<e acute>:

   DIN Standard 5007, "Orden von Schriftzeichenfolgen: ABC-Regeln,"

   April 1991

   IBM Document GG24-3516, "Keys to Sort and Search for Culturally

   Expected Results," Denis Garneau

   "R<e acute>gles du classement alphab<e acute>tique en langue

   fran<c cedilla>aise...", Alain LaBont<e acute>

Additional reference words: 3.00 3.10 softlib ALPHSORT.EXE

KBCategory: kbprg kbfile

KBSubcategory: WIntlDev


SAMPLE: Port Trapping in Windows 3.0/3.1

Article ID: Q100947

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0

   and 3.1

--------------------------------------------------------------------

SUMMARY

=======

In enhanced mode Windows, the I/O permission bitmap (IOPM) is used by

the virtual machine manager (VMM) to determine whether I/O is

permitted at a given I/O port. The IOPM is clear when the VMM is

initialized, which means that any I/O port can be accessed. VxDs can

trap specific I/O ports to prevent direct access. Therefore, unless a

VxD traps a port, direct I/O access is permitted. In standard mode,

the IOPM is not used, so direct I/O access is always permitted. This

does not apply to Windows NT.

The sample IOPORT.ZIP lists ports trapped by the standard VxDs

included in enhanced mode Windows (IOPMPORT.XLS and IOPMPORT.TXT), and

an MS-DOS program IOPM.EXE, which lists all currently trapped ports.

Also, the DT (dump TSS) command in WDEB386 lists all currently trapped

ports.

Download IOPORT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for IOPORT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download IOPORT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get IOPORT.EXE

MORE INFORMATION

================

The IOPM is contained in the task state segment (TSS). The I/O

privilege level (IOPL) and the I/O permission bitmap determine whether

a task is allowed to perform I/O. The IOPL determines the minimum

privilege level required to perform I/O without checking the

permission bitmap. For example, if IOPL = 1, then a procedure must

have a code privilege level (CPL) of 1 or 0 (zero) to perform

unrestricted I/O. However, if the CPL of the current task is greater

than the IOPL, or the processor is operating in virtual 8086 mode,

then the I/O permission bitmap is checked to determine whether I/O is

permitted at the requested port.

In enhanced mode Windows, CPL is always greater than IOPL, so the IOPM

is always checked to determine whether direct I/O access is permitted.

In standard mode, CPL equals IOPL, so the IOPM is never checked.

Each bit in the bitmap corresponds to an I/O port byte address. For

example, the bit for port address 60 (decimal) corresponds to the 60th

bit, or the 4th bit in the 8th byte of the bitmap. In enhanced mode

Windows, the bitmap is always 8192 bytes, and the bitmap is

initialized to allow I/O at any port.

When a VxD is initialized, it can call Install_IO_Handler to trap

specific I/O ports. Install_IO_Handler sets the corresponding bits in

the IOPM. When a trapped port is accessed, the VxD I/O handler will

take over and perform the appropriate action. Windows maintains a

single TSS for all VMs. When a VM switch occurs, the TSS IOPM is

updated to reflect the local IOPM of the incoming VM. Port trapping

for a specific port may be disabled locally or globally from a VxD by

calling Disable_Local_Trapping or Disable_Global_Trapping.

Additional reference words: 3.10 softlib IOPORT.ZIP

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: Reading the Boot Sector of a Drive

Article ID: Q102870

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

BOOTSEC demonstrates how to use Interrupt 25h (absolute disk read) to

read the boot sector (the first sector on head 0, cylinder 0) off of a

drive (either a floppy disk drive or hard disk).

BOOTSEC checks to see whether the drive is one of the following:

   Drive            Detection Method

   ---------------------------------

   CD-ROM           Interrupt 2F calls to MSCDEX.

   Net drive        Windows API WNetGetConnection().

   RAM drive        Checks the boot sector to see if there is one FAT.

   Hard disk        Checks the media BYTE of the boot sector. If it is

                    equal to 0xF8h then it is a hard disk.

   Floppy disk      Checks the media BYTE of the boot sector. If it is

                    not equal to 0xF8h and it is not a RAM drive, net

                    drive, or CD-ROM drive, then it is a floppy disk drive.

BOOTSEC also shows how to implement a dialog box as a main window

using a private dialog class.

MORE INFORMATION

================

The following information is contained in the boot sector:

 - The jump instruction to the boot strap routine

 - The name of the OEM and the version of MS-DOS

 - Bytes per sector

 - Sectors per cluster

 - Reserved sectors

 - Number of file allocation tables

 - Number of root directory entries

 - Number of sectors

 - Media descriptor

 - Number of sectors occupied by each FAT

 - Number of sectors on a single track

 - Number of read/write heads on the drive

 - Number of hidden sectors

 - Number of huge sectors

 - Whether the disk is the first hard disk drive

 - The boot signature

 - The volume serial number

 - The volume label

 - The file system type

NOTE: The information contained in the boot sector was changed in

MS-DOS 5.0. If this program is run on a disk that was formatted with a

previous version of MS-DOS, then some of the fields in the structure

will not be filled out, and the program may display garbage. The

elements of the structure that were not changed will be displayed

correctly.

Download BOOTSEC.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BOOTSEC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BOOTSEC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BOOTSEC.EXE

Additional reference words: 3.10 INT softlib BOOTSEC.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrFileIO


SAMPLE: Mini Title Bars for Windows

Article ID: Q103208

-

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

ItsyBitsy: Mini Title Bars for Windows

Charlie Kindel, Microsoft Premier Support Services

Kyle Marsh, Microsoft Developer Network Technology Group

Created: February 16, 1993

Abstract

--------

In Microsoft Windows, the standard size of a window's title bar is based on

the size of the current system font and cannot be changed. Some

applications (for example, Microsoft Visual Basic and Microsoft Excel) have

toolboxes consisting of windows with smaller title bars. This article

describes how you can use the itsybitsy functions to implement small title

bars in windows.

The ItsyTest sample application demonstrates the use of the itsybitsy

functions.

In Microsoft Windows, the standard size of a window's title bar is based on

the size of the current system font and cannot be changed. Some

applications (for example, Microsoft Visual Basic and Microsoft Excel) have

toolboxes consisting of windows with smaller title bars. ItsyTest

demonstrates how you can use the itsybitsy functions to implement small

title bars in windows.

Download ITSYBITS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ITSYBITS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ITSYBITS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ITSYBITS.EXE

Additional reference words: 3.10 softlib ITSYBITS.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrWndw


SAMPLE: Desiging DLLs for Multiple Client Applications

Article ID: Q103210

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

Designing DLLs for Multiple Client Applications, Part 2: Implementation

David Long

Microsoft Developer Network Technology Group

Created: April 21, 1993

Abstract

--------

This is a companion article to "Designing DLLs for Multiple Client

Applications, Part 1: Strategy," also available on the Microsoft

Developer Network CD. That article discusses various strategies for

allowing Microsoft Windows dynamic-link libraries (DLLs) to provide

services to multiple client applications.

This article describes how the associated Grocery Shopper sample

application implements some of the client-server strategies described

in Part 1. It begins with an overview of the sample application's

architecture, and then proceeds to analyze how the application

programming interface (API) is implemented, how the DLL manages

multiple clients, and how information hiding is enforced. Among the

features of the sample code are registration and unregistration APIs,

enumeration callbacks, delayed resource allocation, and custom

event-notification messages.

Download DLLSTRT2.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DLLSTRT2.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DLLSTRT2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DLLSTRT2.EXE

Additional reference words: 3.10 softlib DLLSTRT2.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: Printing in Visual Basic and C

Article ID: Q103213

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

EZPRINT: No-Frills Printing in Visual Basic and C

Dennis Crain

Microsoft Developer Network Technology Group

Created: April 19, 1993

Abstract

--------

Printing from applications written for the Microsoft Windows version

3.1 operating system can be trying at times. This article describes a

convenient method for printing from applications using a dynamic-link

library (DLL) called EZPRINT.DLL. EZPRINT provides three exported

functions--StartDocument, PrintObject, and EndDocument--to start the

printing job, print various objects on the page, and end the printing

job. The sample DLL code and Visual Basic code that calls EZPRINT are

included with this article. You may use the DLL as is or modify it to

meet your needs. In its present form, EZPRINT prints text, rectangles,

and lines with various attributes.

This article was written for developers who have relatively little

printing experience and whose printing needs involve text placement

and simple line drawing only. Experienced developers can also use

EZPRINT as a framework for implementing more sophisticated printing

capabilities.

Download EZPRINT.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EZPRINT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EZPRINT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EZPRINT.EXE

Additional reference words: 3.10 softlib EZPRINT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


SAMPLE: Updating the Screen Without Flicker

Article ID: Q103214

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Flicker-Free Displays Using an Off-Screen DC

Herman Rodent

Microsoft Developer Network Technology Group

Created: April 5, 1993

Abstract

--------

This article describes a technique for drawing to a window device

context (DC) in such a way that the screen does not flicker. The

technique is very simple and easy to implement.

Many applications written for the Microsoft Windows operating system

maintain status information such as the current time in a small control

window that flickers very annoyingly each time it's updated. All standard

Windows controls flicker if updated at frequent intervals. The solution to

this problem is to implement a simple control and use an off-screen device

context (DC) to construct the image, which is then copied in total to the

client area of the control window. The net result is a control that can be

updated without causing any flicker.

FLICKER has window procedures for two controls--one of these flickers;

the other one doesn't. The application creates an instance of each of

these controls and updates the window text ten times every second to

show how one flickers and the other doesn't. Both controls support the

system text color, window background color, and the WM_SETTEXT and

WM_SETFONT messages.

Download FLICKER.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FLICKER.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FLICKER.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FLICKER.EXE

Additional reference words: 3.10 softlib FLICKER.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiDrw


SAMPLE: Animation in Windows

Article ID: Q103215

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Animation in Windows

Herman Rodent

Starring:  Nell and Olivia, the Wonder Dog

Created: April 28, 1993

Abstract

--------

This article is aimed at people who would like to create a Microsoft

Windows-based application that does some form of animation, or who

would like to understand how to improve the performance of an existing

animated application, or who are considering porting an MS-DOS--based

application to Windows. The main focus of the article is on using

device-independent bitmaps (DIBs) for the images and the DIB driver

(DIB.DRV) for the off-screen image buffer. The article is written

around a sample application, Sprites, which is included with the

article. Some knowledge of animation techniques is assumed. If you're

looking for a "How to Do Animation" article, this isn't it. The

following points are covered:

 - Using the DIB driver

 - Palettes

 - Measuring and improving performance

 - Lots of useful little tips and hints

SPRITES demonstrates sprite (cast-based) animation in a Microsoft

Windows-based application using device-independent bitmaps (DIBs)

for the images and the DIB driver (DIB.DRV) for the off-screen image

buffer.

The SPRITES application uses a DIB for a background scene, and allows

you to load multiple sprites on top of the background scene. Each

sprite has x, y, and z coordinates, optional x and y velocity, and a

flag that indicates whether it can be dragged by the mouse.

A background and a set of sprites can be combined into a scene

described in a simple INI file. You can load the entire scene by

choosing the Load Scene command from the File menu.

The application updates the positions of all sprites that have a

non-zero velocity as fast as it can, using a PeekMessage() loop. Sprites

that have the selectable attribute set can be dragged with the mouse.

Double-clicking a sprite brings up a dialog box for setting sprite

attributes.

Download SPRITES.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SPRITES.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SPRITES.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SPRITES.EXE

Additional reference words: 3.10 softlib SPRITES.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiMisc


SAMPLE: Synchronizing Applications with CD Audio

Article ID: Q103217

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Using MCI to Synchronize a Windows-Based Application with CD Audio

Herman Rodent

Microsoft Developer Network Technology Group

Created: February 10, 1993

Abstract

--------

This technical article describes a simple technique that uses the

Media Control Interface (MCI) to synchronize events in a Microsoft

Windows-based application with audio from a CD. The following topics

are covered:

 - MCI message interface

 - Audio CD time formats

 - Owner-draw graphical buttons

 - Extending the idea to other time sources

Four pieces of sample code included with this article create four

applications: PLAYACD, a simple CD controller; SINGACD, a sing-along

application that shows the lyrics to a CD as it plays; TIMEACD, an

authoring tool to create the lyric files used by the sing-along

application; and SINGAWAV, an application that demonstrates

synchronizing to a waveform.

The SINGACD sample application shows how to use the media control

interface (MCI) to synchronize an application with CD audio in

Microsoft(R) Windows(TM).

SINGACD displays a moving ball above the lyrics of a song. The ball

moves in time with the music and (ideally) stays above the current

word in the song. Achieving this synchronization involves a two-part

process: The first part involves displaying the entire line of text at

the right time; the second part involves placing the ball over the

correct word in the line.

SINGACD has the following components:

 - The PLAYACD application is a very simple controller for the MCI CD

   audio device.

 - The TIMEACD application is a tool for authoring lyric files.

 - The SINGAWAV sample is a modified version of SINGACD that opens and

   plays a specific wave file and lyric file.

Download SINGACD.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SINGACD.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SINGACD.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SINGACD.EXE

Additional reference words: 3.10 softlib SINGACD.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMCDROM


SAMPLE: Testing to See if a Drive is a CD-ROM

Article ID: Q103219

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

ISCDROM: Demonstrates Testing if Drive is CD-ROM

ISCDROM is an assembly code fragment which demonstrates how to

determine if a drive is a CD-ROM drive.

ISCDROM is a companion source code fragment to the technical article,

"CD-ROM Design and Optimization." Please reference this article for

more information.

Download ISCDROM.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ISCDROM.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ISCDROM.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ISCDROM.EXE

Additional reference words: 3.10 softlib ISCDROM.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDsk


SAMPLE: Trapping System RIPs and Other Notification Messages

Article ID: Q103223

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Ripwatch: Traps System RIPs and Other Notification Messages

Ripwatch uses the TOOLHELP dynamic-link library (DLL) to trap system

RIPs and other notification messages, and displays them in a window.

When developing Microsoft(R) Windows(TM)-based applications, you

should always use the debugging version of Windows. This special build

of the system is distributed with the Windows Software Development Kit

(SDK). It tests for invalid parameters to Windows function calls and

reports other problems such as failing to free graphics device

interface (GDI) objects when an application exits. If you don't know

about the debugging version, you are not getting the most from your

SDK; worse still, you may be preparing to ship a potentially faulty

product.

The default action for reporting detected errors is to send a message

to a debug terminal connected to COM1. This requires that you have a

terminal attached to the port to see these messages. This can be a

waste of desktop space, a source of annoying beeps,and may tie up an

otherwise useful communications port. The TOOLHELP.DLL included with

the Windows SDK allows you to hook these messages before they reach

the communications port. The Ripwatch sample application displays the

messages in a window. The display includes a textual description of

the RIP error code. Ripwatch also allows you to copy the text to the

Clipboard, save it in a file, or print it.

There is a known problem when running Ripwatch with Microsoft

CodeView(R) for Windows. If you try to start CodeView while Ripwatch

is running, CodeView reports an out-of-memory condition. If you try to

start Ripwatch after CodeView has been started, CodeView will usually

GP fault.

Ripwatch was built and tested under Microsoft Windows version 3.1 and

the Microsoft C/C++ version 7.0 compiler.

Download RIPWATCH.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RIPWATCH.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RIPWATCH.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RIPWATCH.EXE

Additional reference words: 3.10 softlib RIPWATCH.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: Processing Nonclient Messages with Msg Blaster Control

Article ID: Q103225

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Smallcap: Uses Message Blaster Control to Process Nonclient Messages

Smallcap is a sample application created by Randall Kern and Jim Cash

that accompanies the "Message Blaster: Processing Messages in Visual

Basic" technical article on the Microsoft(R) Developer Network CD.

The Microsoft Visual Basic(TM) development environment is not based on

a message-driven programming model. Instead, Visual Basic supports a

predefined set of events for each object (form or control) that you

create. An application written in Visual Basic cannot respond to

messages from Microsoft Windows(TM) that are not handled directly by a

Visual Basic event. The Message Blaster is a Visual Basic control that

addresses this restriction by allowing you to catch and process

Windows messages from Visual Basic.

You can use the Message Blaster control to process any message from

Windows except for WM_CREATE and WM_NCCREATE messages. The Smallcap

sample application shows how you can process WM_NC* (nonclient)

messages to create captions.

Smallcap was built and tested under Microsoft Windows version 3.1 and

Microsoft Visual Basic version 2.0.

Download SMALLCAP.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SMALLCAP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SMALLCAP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SMALLCAP.EXE

Additional reference words: 3.10 softlib SMALLCAP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrMsg


SAMPLE: Mixed-Language Application (VB, COBOL, SQL)

Article ID: Q103226

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

VBCOBSQL: Demonstrates a Mixed-Language (Visual Basic-COBOL-ESQL)

Application

You can use Microsoft(R) Visual Basic(TM), Microsoft COBOL, and

Microsoft SQL Server to build full-featured client-server applications

that use the strengths of each product. Visual Basic creates the

graphical user interface. Subroutine calls are made in the Basic code

to COBOL dynamic-link libraries (DLLs). The COBOL DLL contains

Embedded SQL (ESQL) to request the necessary data from the SQL Server.

The COBOL DLL manipulates the retrieved data as required, then passes

the data back to Visual Basic. In other words, Visual Basic is the

graphical front-end and COBOL DLL is the back-end of the client

application.

VBCOBSQL uses the PUBS database from the SQL Server package. The demo

makes several queries to the PUBS database, such as Author Search and

List Publications in a Category. It also allows you to insert and

delete authors and add new publications to the database.

To build VBCOBSQL, you will need Visual Basic version 2.0 Professional

Edition, Microsoft COBOL version 5.0 or Micro Focus(R) COBOL version

3.0, and Embedded SQL Toolkit for COBOL.

In Visual Basic, load the VBCOBDEM.MAK project and build an .EXE file

for the application. Before building the COBOL DLL that accesses SQL

Server, make sure that your build environment is set up to build

COBOL/SQL Server applications. Set the LIB environment variable to

include the drive and path of the following files:

 - LCOBOLW.LIB (supplied with the COBOL compiler)

 - COBW.LIB (supplied with the COBOL compiler)

 - SQLAKW.LIB (supplied with Embedded SQL for COBOL)

 - W3DBLIB.DLL (supplied with Embedded SQL for COBOL)

You also need the object file, CBLWINA.OBJ, supplied with the COBOL

compiler. You must specify "Mixed Language Support" when you install

this file from the COBOL disks.

Next, edit the VBCOBSQL.DIR directives file to use your own server,

database, user ID, and password. There are two ways to build the DLL:

 - Run COBC.BAT and COBL.BAT, in that order. The first batch file

   compiles the DLL and the second links it. VBCOBSQL.DLL will be

   created.

 - Build the DLL using Programmer's WorkBench (PWB). This sample

   includes the VBCOBSQL.MAK make file to allow you to build with PWB.

Make sure that this DLL is in your current directory or in your PATH.

For more information on building DLLs, see "COBOL Programming for

Windows," Chapter 2 (Building Dynamic Link Libraries) included with

Microsoft COBOL or the Micro Focus(R) COBOL User's Guide.

Before running the demo, make sure that the following files are in

your current directory or in your PATH:

 - SQLAKW.DLL  (provided with Embedded SQL toolkit for COBOL)

 - W3DBLIB.DLL (provided with Embedded SQL toolkit for COBOL)

 - DBNMP3.DLL  (provided with Embedded SQL toolkit for COBOL)

 - CBLWIN.DLL  (provided with the COBOL compiler)

 - CBLSSEG.DLL (provided with the COBOL compiler)

 - VBRUN200.DLL (provided with Visual Basic version 2.0)

To run the demo, run the executable file you created in Visual Basic.

You can also run the demo interactively in Visual Basic. In the login

screen, fill in the fields required to log into the PUBS database. If

the login is successful, you will be in the demo. You can then select

SQL options from the menu to perform the search/update operations. Use

the Help menu items to get more information on using the demo and

building mixed-language client-server applications.

VBCOBSQL is a companion application for the "Building VB/COBOL/ESQL

Mixed-Language Applications" technical article on the Microsoft

Developer Network CD.

Download VBCOBSQL.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for VBCOBSQL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download VBCOBSQL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get VBCOBSQL.EXE

Additional reference words: 3.10 softlib VBCOBSQL.EXE

KBCategory: kbprg kbfile

KBSubcategory: GenSDK


SAMPLE: Visual Basic Using Windows DLLs

Article ID: Q103227

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

VBFILEIO: Demonstrates Visual Basic with Windows DLLs

VBFILEIO gives Microsoft(R) Visual Basic(TM) applications access to C

run-time stream input/output (I/O) functions. The sample also

demonstrates linking to a dynamic-link library (DLL) function from

Visual Basic and using Visual Basic data types as parameters.

VBFILEIO is a companion sample application for the "Extending Visual

Basic with Microsoft Windows DLLs" technical article on the Microsoft

Developer Network CD.

VBFILEIO was created using Microsoft Visual Basic version 2.0 and

Microsoft C/C++ version 7.0.

Download VBFILEIO.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for VBFILEIO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download VBFILEIO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get VBFILEIO.EXE

Additional reference words: 3.10 softlib VBFILEIO.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrDll


SAMPLE: DDE Communication Over a Network

Article ID: Q103228

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

VBSource and VBDest: Demonstrate DDE Communication Over a Network

The VBSource and VBDest sample applications demonstrate how

applications can communicate over the network using Network Dynamic

Data Exchange (Network DDE). These sample applications accompany the

"Reach Out and Exchange: A Network DDE Overview," "Browsing for

Network Servers in C and Visual Basic," and "Learning to Share:

Network DDE Shares and Visual Basic" technical articles on the

Microsoft(R) Developer Network CD.

VBSource and VBDest were built and tested under Microsoft Windows(TM)

version 3.1 and Microsoft Visual Basic(TM) version 2.0.

Download NETBONES.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for NETBONES.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NETBONES.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NETBONES.EXE

Additional reference words: 3.10 softlib NETBONES.EXE

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: UsrNetDde


SAMPLE: DDE Client Over a Network

Article ID: Q103230

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SoundCli: Demonstrates DDE Client Over Network

SoundCli is a companion sample application for the "Network DDE and

Multimedia Combine to Let You Talk to Your Peers" technical article on

the Microsoft(R) Developer Network CD. Two sample applications

accompany this article: SoundSrv, a Visual Basic(TM) application,

demonstrates the internal sounds of the server, and SoundCli, a

dynamic data exchange (DDE) client application, enables a WAVE file or

live sound to be sent over a network via DDE to a remote machine

running the sound server.

The client application (SoundCli) allows you to open WAVE files and

play them on the local machine or on a remote machine. It also allows

you to send whatever sound input is available on the local machine to

the remote machine. For example, if you have a microphone connected to

the machine running the client, you can talk live to the remote

machine running the server.

The SoundCli application was constructed using the W16APP sample

available on the Developer Network CD (Sample Code, Technical Article

Samples, Misc. Samples).

To play with the samples, you will need two machines equipped with

sound cards running Microsoft Windows(TM) for Workgroups and connected

to a network.

SoundCli was built and tested under Microsoft Windows version 3.1 and

Microsoft Visual Basic version 2.0.

Download SOUNDCLI.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SOUNDCLI.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SOUNDCLI.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SOUNDCLI.EXE

Additional reference words: 3.10 softlib

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: UsrNetDde


SAMPLE: Moving an Item in a List Box Using Drag and Drop

Article ID: Q103318

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

MOVELST demonstrates how to reorder the items in a list box using drag

and drop. The user clicks an item, drags it to the new position, and

drops the item. The list box will scroll if necessary.

MOVELST also shows how to implement a dialog box as a main window

using a private dialog class.

The drag and drop implementation is based on the sample application

LISTDRAG.

Download MOVELST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MOVELST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MOVELST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MOVELST.EXE

Additional reference words: 3.10 listbox softlib MOVELST.EXE

KBCategory: kbprg kbfile

KBSubcategory:  UsrDnd


SAMPLE: Retrieving Status of Text Box Using Windows Messages

Article ID: Q103337

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

EDIT_INFO: Retrieves Status of Text Box Using Windows Messages

EDIT_INFO shows how to access retrieval information from a

Microsoft(R) Visual Basic(TM) application. It uses Microsoft

Windows(TM) functions to retrieve information about the status of a

text box. The Visual Basic language does not provide this capability.

EDIT_INFO allows you to use the Windows message constants listed below

for the following tasks:

 - EM_GETLINE: Copy a specific line of text from the edit control.

 - EM_GETLINECOUNT: Retrieve the number of lines within the edit control.

 - EM_GETSEL: Position the cursor at a specific character location.

 - EM_LINEFROMCHAR: Retrieve the line number of a specific character

   location.

 - EM_LINEINDEX: Retrieve the number of lines prior to a specified

   character position.

 - EM_LINELENGTH: Retrieve the number of characters in a specified

   line.

 - EM_REPLACESEL: Replace the specified text with another text string.

For information on specifying the amount of text allowed within a text

control, search the Knowledge Base for EM_LIMITTEXT.

For information on setting tab stops within a control, search the

Knowledge Base for EM_SETTABSTOPS.

EDIT_INFO was built and tested under Microsoft Windows version 3.1 and

Visual Basic version 3.0.

Download EDTINFO.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EDTINFO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EDTINFO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EDTINFO.EXE

Additional reference words: 3.10 softlib EDTINFO.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: BitBlt and StretchBlt Animation

Article ID: Q103339

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

FLIP: Demonstrates BitBlt and StretchBlt Animation

FLIP is a Visual Basic(TM) program that uses the BitBlt and StretchBlt

functions to animate graphics. The program simulates flipping tiles.

BitBlt copies icons instead of using individual picture boxes.

StretchBlt also copies bitmaps from a source to a destination, but

compresses or stretches the original bitmap.

To load FLIP files in the Visual Basic environment, run VB.EXE, choose

Open Project from the File menu, and select the FLIP.MAK file.

FLIP was built with Microsoft(R) Visual Basic version 3.0 and tested

under Microsoft Windows(TM) version 3.1.

Download FLIP.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FLIP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FLIP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FLIP.EXE

Additional reference words: 3.10 softlib FLIP.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: GDI Region, Clipping, and Bitmap Functions

Article ID: Q103341

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

JIGSAW: Demonstrates GDI Region, Clipping, and Bitmap Functions

JIGSAW uses region functions (CreateRectRgn, CombineRgn, SetRectRgn),

clipping functions (SelectClipRgn), and bitmap functions (BitBlt) from

the Microsoft(R) Windows(TM) graphics device interface (GDI) to

simulate a jigsaw puzzle.

These functions use less memory and fewer resources than individual

picture box controls to display and move the different pieces of the

puzzle around the window.

Region functions create, alter, and retrieve information about regions

that can be filled with graphical output. You can use region functions

with clipping functions to create clipping regions. A clipping region

is a portion of a window where GDI creates output. If you send output

to an area of a window outside a clipping region, the output will not

be visible. Bitmap functions display bitmaps; these functions let you

prepare images in memory and then copy the images to the display.

To load JIGSAW files in the Visual Basic(TM) environment, run VB.EXE,

choose Open Project from the File menu, and select the JIGSAW.MAK

file. You can also make an executable file and run it as a separate

program using the Visual Basic run-time file VBRUN200.DLL.

JIGSAW was built with Microsoft Visual Basic version 3.0 and tested

under Microsoft Windows version 3.1.

Download JIGSAW.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for JIGSAW.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download JIGSAW.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get JIGSAW.EXE

Additional reference words: 3.10 softlib JIGSAW.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiMisc


SAMPLE: File Input and Output in Visual Basic

Article ID: Q103342

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Kwikzone: Demonstrates File Input and Output in Visual Basic

Kwikzone is a Visual Basic(TM) version 3.0 program that shows state

and city area codes.

Download KWIKZONE.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for KWIKZONE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download KWIKZONE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get KWIKZONE.EXE

Additional reference words: 3.10 softlib KWIKZONE.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrFileIO


SAMPLE: Using DDE to Create Program Manager Groups and Items

Article ID: Q103343

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Mkegroup: Uses DDE to Create Program Manager Groups and Items

The Mkegroup (Make Group) sample application demonstrates the ease of

creating Microsoft(R) Windows(TM) Program Manager groups and items

with dynamic data exchange (DDE).

The application displays a form from which the user can select a

program group name (for example, Games) and a bunch of files. Clicking

on the Make Group button either creates a new group with the specified

name in the Program Manager or opens a group by that name, if one

already exists. The application then creates program items in the

group for each selected file.

Of course, the user can create groups and items manually using the

Program Manager File New command or by dragging files from the File

Manager to the Program Manager. However, as an added bonus, Mkegroup

provides an Iterate button that scans all of the subdirectories below

the current directory, looking for files that match the currently

selected pattern (for example, *.EXE), and adds all matching files to

the list of selected files.

For example, let's say you have a directory called C:\VB\VBSAMPLE on

your hard disk that contains a subdirectory for each sample program

you have written. If you want to create a program group that contains

program items for all of the samples, open Mkegroup, select

C:\VB\VBSAMPLE in the directory list box, and choose the Iterate

button. This is much easier than opening each subdirectory

individually.

Download MKEGROUP.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MKEGROUP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MKEGROUP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MKEGROUP.EXE

Additional reference words: 3.10 softlib MKEGROUP.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrExt


SAMPLE: Demonstrates BitBlts to Shuffle Around the Screen

Article ID: Q103345

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

Shuffle: Demonstrates BitBlts to Shuffle Around the Screen

Shuffle is a Visual Basic(TM) version 3.0 sample that uses Windows(TM)

BitBlts to shuffle around the screen (similar to IdleWild).

Download SHUFFLE.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SHUFFLE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SHUFFLE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SHUFFLE.EXE

Additional reference words: 3.10 softlib SHUFFLE.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Code Demonstrates Dynamic Child Dialog Boxes

Article ID: Q103375

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

The Visual C++ Project Compiler and Project Linker dialog boxes, and the

Word for Windows version 2.0 Options dialog box, demonstrate dynamic child

dialogs--dialogs boxes within dialogs boxes, which dynamically appear based

on a list box selection. This article discusses how to implement these

dynamic child dialog boxes. MULTIDLG is a file in the Microsoft Software

Library that demonstrates one of the techniques discussed in this article.

The new Windows 95 style DS_RECURSE should make this process unnecessary.

It is only useful for Win 3.x compatibility.

Download MULTIDLG.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MULTIDLG.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MULTIDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MULTIDLG.EXE

MORE INFORMATION

================

A dynamic child dialog box generally contains a list box at the left, which

determines what subdialog box is displayed in the right side of the dialog

box. This interface structure is helpful when managing very large

interfaces with options that intuitively break into categories. The Word

for Windows Options dialog box and Visual C++'s Compiler and Linker dialog

boxes are good examples of complex interfaces made manageable by the use of

dynamic child dialog boxes.

Possible implementations for dynamic child dialog boxes can be divided into

two categories. One approach--often the first one to come to mind--involves

embedding a dialog box, which has the WS_CHILD style, into a second, larger

dialog box. At first, this approach's modularity appears to be big plus;

that is, because the child dialog boxes are actual dialog boxes, each one

gets its own dialog box procedure and resource script definition. There is

a major problem in this approach, however, in that limitations of

IsDialogMessage() prevent it from operating on windows whose controls

extend more than one level deep. Because the controls on the WS_CHILD

dialog boxes are children of a child of the main dialog box, simply adding

IsDialogMessage() with the main dialog box's handle to the message loop

won't cover mnemonic, tabbing, and other dialog box functionality for these

controls. Working around these problems can be difficult.

The second approach does not use a true WS_CHILD dialog box. Instead, it

conditionally creates and destroys (and/or hides and shows) groups of

controls on a single dialog box, based on the list box selection. This

approach does not suffer from the tabbing and mnemonic problems of the

WS_CHILD dialog approach. Additionally, with some cleverness, both the code

and the resource script can be as modular as the WS_CHILD dialog box

approach.

Developers should be aware of the stress dynamic dialog boxes can place on

USER's heap space. Each control created consumes some of this, and a normal

Windows dialog box may consume as much as 3 percent or more of this shared

system resource. However, a dynamic child dialog box creates many more

controls compared to a normal dialog box. Most of these controls are hidden

at any one time, and are made visible only when their particular child

dialog box is shown. While they may be hidden, they consume just as much

USER heap, and therefore it's easy to imagine how a complex dynamic child

dialog box could use 15 percent or more of the available USER heap space.

Obviously, the developer must beware of consuming so much of a scarce

system resource. To address this concern, MULTIDLG creates the controls of

a particular dynamic child dialog box only if and when that dialog box

needs to be displayed. If the user doesn't pick a particular list box

option, the controls for that option aren't created. Note that MULTIDLG

just hides created controls when another child dialog box is chosen. A more

complex implementation of dynamic child dialog boxes should destroy

inactive controls, to fully reclaim the USER heap space they consume. The

down side of this is that the application is required to record the state

of each control within a particular dynamic child dialog box before killing

it, and to reset each control's state if the subdialog box is chosen again.

In contrast, if the controls aren't killed when the dynamic child dialog

box is deselected, the state information can be conveniently extracted from

the controls themselves when the user chooses the OK command button, even

though these controls are invisible.

MULTIDLG implements dynamic child dialog boxes by loading and parsing

dialog box resources and creating their controls manually on a larger, main

dialog box. When another subdialog box is chosen, MULTIDLG hides all the

controls of the existing dialog box before showing the new selection's

controls (creating them from their template as well, if necessary).

MULTIDLG uses these steps to create the controls on the main dialog

box:

1. If the group of controls has not been loaded before, load the

   dialog box resource in which they reside, via FindResource() and

   LoadResource().

2. Parse the control information out of the dialog box resource using

   the DialogBoxHeader and ControlData structures as guides. (These

   structures are not defined in WINDOWS.H. Because they contain

   variable-length fields, they can't really be represented as C

   structs. You can find information about these structures in the

   Windows 3.1 SDK online documentation, under "Dialog Box Resource".)

3. Determine the coordinates of the controls within the main dialog

   box by converting their dialog units into pixels, and call

   CreateWindow() on each.

NOTE: A bug in IsDialogMessage() prevents mnemonics from working

correctly when a hidden control shares a mnemonic with a visible

control. To work around this, MULTIDLG captures the window text from

appropriate controls as they are being hidden, and resets this window

text to nothing. When the control is becoming visible again, the code

resets the text to what it was. This prevents IsDialogMessage() from

seeing the mnemonic of the hidden control.

Additional reference words: 3.10 DialogBoxIndirect listbox softlib

MULTIDLG.EXE

KBCategory: kbprg kbfile

KBSubCategory: UsrDlgs


SAMPLE: Rebooting an MSSetup Script on User Request

Article ID: Q103399

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

The MSSetup Toolkit does not provide a way for the user to arbitrarily and

cleanly reboot the computer without having the RestartListEmpty function

return 0 (zero). The NSETUP sample provides a work around for this

situation by providing a mechanism for the user to communicate with the

MSSetup dynamic-link libraries (DLLs) to cleanly reboot the computer

without having a system file on the RestartList.

Download NSETUP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for NSETUP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NSETUP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NSETUP.EXE

MORE INFORMATION

================

The MSSetup Toolkit occupies a relatively small footprint in memory while

providing much of the functionality needed to author a full-featured

installation program. MSSetup accomplishes this low memory requirement by

having a small fixed code stub program (SETUP.EXE) copy over the larger

DLLs to a temporary directory on the user's hard disk. When the script

exits, this small fixed code stub cleans up after the installation script

by deleting the DLLs from the user's temporary directory.

Another feature built into the MSSetup Toolkit is the ability to let the

user install system level DLLs while they are loaded in memory at the time

of installation. MSSetup accomplishes this by maintaining a list of files

that need to be installed while Windows is rebooted. The MSSetup script

author accomplishes this by calling the MSSetup functions RestartListEmpty

and ExitExecRestart.

There is no functionality built into the MSSetup Toolkit, however, to allow

the user to arbitrarily reboot Windows. A cursory examination of this

situation might yield a workaround involving the call to Windows-based

application programming interface (API) ExitWindows or ExitWindowsExec via

the MSSetup script. However, there is a problem with this approach. Upon

rebooting the system, the user will find all the MSSetup DLLs still present

in the temporary directory. Because Windows exits more or less immediately

upon the call to ExitWindows or ExitWindowsExec, the Setup stub program

(SETUP.EXE) never has a chance to perform its cleanup (see paragraph

above). To expect the installation script to provide this type of

functionality further complicates the situation.

Another approach to the situation is to let MSSetup handle the cleanup as

it would normally. NSETUP launches SETUP.EXE and waits for it to clean up

and terminate. In this manner, NSETUP relies on SETUP.EXE's behavior to

delete the files in the temporary directory. The sample also demonstrates a

technique for communicating between the MSSetup script and the NSETUP

program via the Windows function RegisterWindowMessage.

In many ways, the NSETUP sample is similar to SETUP.EXE; it is a fixed code

stub program, which WinExecs SETUP.EXE and then waits in the background for

the program to finish. When SETUP.EXE finishes, NSETUP consults a reboot

flag set via a message sent from the MSSetup script. If the user has chosen

to reboot, NSETUP makes a call to ExitWindows.

Additional reference words: 3.10 MSSetup tool kit softlib NSETUP.EXE

KBCategory: kbtool kbfile

KBSubcategory: TlsMss


SAMPLE: Subclassing VBX Controls with MFC 2.0

Article ID: Q103856

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

SUMMARY

=======

SUBVBX is a sample application that does Windows subclassing on a VBX

control using the Microsoft Foundation Class (MFC) Libraries version 2.0.

The sample subclasses the grid control, overrides the OnDlgCode() message

handler, and returns the DLGS_WANTARROWS code. Normally Windows uses the

arrow keys to move between controls in a dialog box, and does not pass the

arrow keys to the control. Subclassing the grid control and overriding the

OnDlgCode() message handler causes Windows to pass the arrow keys to the

grid control so that it can use the keys to move between cells in the

control.

Download SUBVBX.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SUBVBX.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SUBVBX.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SUBVBX.EXE

MORE INFORMATION

================

Windows controls, such as an edit control or a list box control, can be

subclassed in MFC using the CWnd::SubclassWindow() and

CWnd::SubclassDlgItem() functions. These functions do not work for VBX

controls. These functions rely on the fact that each window control has its

own Windows procedure. This way it is possible for an MFC object to chain

to the control's original Windows procedure. However, Visual Basic (VB)

controls under MFC 2.0 are managed by MFC objects, and therefore VB

controls use the same Windows procedure as all other MFC objects.

To subclass a VB control in MFC 2.0, it is necessary to copy the data from

the original control object into the object that you want to use to

subclass the original control. After the original object has been copied,

it can be detached and deleted, and the new control object can be attached.

This sample defines the CVBClone class that contains the function

SubclassVBControl(). This function does the copying, attaching, and

detaching that is described above. To use this class, derive a new class

from the CVBClone class and new message handling functions to the message

map. This class can then be used to subclass a VB control in a dialog box

by calling the SubclassVBControl() function in the OnInitDialog() or

OnInitialUpdate() function of the dialog box or form view that contains the

control.

This sample subclasses a grid control in a form view. The sample defines

the CMyGrid class from CVBControl, which it uses to subclass the control.

The sample also calls SubclassVBControl in the OnInitialUpdate() of the

form view to subclass the control in the form view.

Additional reference words: 3.10 softlib SUBVBX.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: INIHEADR Sample Reads Section Headers from .INI Files

Article ID: Q104096

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

SUMMARY

=======

The Windows SDK does not define a function to read all of the section

headers from a profile (.INI) file. An application must read the entire

.INI file and parse it to obtain the section headers.

NOTE: Microsoft recommends using Windows's application programming

interfaces (APIs) to read .INI files. The method described below is not

guaranteed to work on future releases, especially for system .INI files

such as WINFILE.INI, WIN.INI, SYSTEM.INI, CONTROL.INI, and so forth.

The INIHEADR sample defines a function called GetPrivateProfileSections(),

which parses a given .INI file and returns a buffer containing the section

headers separated by NULLs and terminated by a double NULL. SECTION.C

contains the function and a necessary helper function. The sample allows

the user to choose an .INI file using the Open common dialog box. The

section headings are then placed in a list box.

Download INIHEADR.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for INIHEADR.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download INIHEADR.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get INIHEADR.EXE

MORE INFORMATION

================

A profile file (WIN.INI) or a private profile (such as CLOCK.INI) must

have the following form:

   [section heading]

   entry=value

      .

      .

      .

For example, given a profile containing the following section headings

   [windows]

      .

      .

      .

   [Desktop]

      .

      .

      .

   [Extensions]

GetPrivateProfileSections() parses the profile file and places the

following in a buffer:

   windows<NULL>Desktop<NULL>Extensions<NULL><NULL>

Additional reference words: 3.00 3.10 softlib INIHEADR.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrIni


SAMPLE: Sample Demonstrates Read-Only Pop-Up Window w/ Shadow

Article ID: Q104792

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

SUMMARY

=======

The Microsoft Windows SDK "The Windows Interface: An Application

Design Guide" version 3.1 manual describes a read-only pop-up text

field as a text field that, when clicked with the mouse, displays a

read-only pop-up window containing additional information.

ROPOPUP is a file in the Microsoft Software Library that demonstrates how

to implement such a read-only pop-up window to display text. The

sample also demonstrates how to add a shadow to this read-only pop-up

window.

Download ROPOPUP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ROPOPUP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ROPOPUP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ROPOPUP.EXE

MORE INFORMATION

================

In the ROPOPUP sample, a button is used to invoke the read-only pop-up

window. The read-only pop-up window is merely a pop-up window that has

no nonclient areas (caption, system menu, menu, minimize/maximize

buttons, sizing border, and so forth). Text is displayed on the main

part of the pop-up window's client area. A shadow is displayed on the

bottom and right sides of the client area.

Achieving the shadow effect requires several steps:

1. Set the read-only pop-up window class's brush to a NULL_BRUSH.

   NOTE: The NULL_BRUSH is retrieved via GetStockObject(NULL_BRUSH).

   The effect is that the pop-up window will be entirely invisible.

   This step is needed in order to allow the shadow to be partially

   transparent.

2. In the WM_CREATE message case for the pop-up window, create the

   shadow brush pattern. The shadow's pattern is defined by a

   monochrome bitmap with alternating black and white pixels.

3. In the WM_PAINT message case for the pop-up window, three things

   need to be done:

   a. Fill the nonshadow area of the pop-up Window using the Rectangle

      function.

   b. Output the read-only text on the nonshadow area.

   c. Paint the shadow using PatBlt with ROP code 0xA000C9 to combine

      the shadow pattern and the background. For each black pixel in

      the pattern, this ROP code puts a black pixel on the screen. For

      each white pixel in the pattern, the existing screen pixel is

      left untouched. The end result is a shadow-like effect that

      allows the background to partially show through the shadow.

The read-only pop-up window is terminated by any mouse button or

keyboard input. Because all the output for the pop-up window is done

in its client area, no special screen cleanup is needed. Windows

automatically refreshes what lies beneath the pop-up window.

Additional reference words: 3.00 3.10 shadow effect softlib ROPOPUP.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiDrw


SAMPLE: SpawnAndWait DLL Provides Synchronous Spawn Function

Article ID: Q105116

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

--------------------------------------------------------------------

SUMMARY

=======

The sample RUNWAIT demonstrates using TOOLHELP.DLL to provide a dynamic-

link library (DLL) function that spawns applications and waits for their

termination before returning from the function call. The sample is

compatible with Visual Basic (VB) and Windows 3.0. The sample loads a

hidden task at DLL startup time to own the Toolhelp callback.

Download RUNWAIT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RUNWAIT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RUNWAIT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RUNWAIT.EXE

MORE INFORMATION

================

The following is the VB function declaration (this must be on a single line

in VB):

Declare Function SpawnAndWait& Lib "RUNLIB.DLL" (ByVal parenthwnd%,

ByVal lpszOp$, ByVal lpszFile$, ByVal lpszParams$, ByVal lpszDir$,

ByVal nShow%)

DWORD SpawnAndWait(hwnd, lpszOp, lpszFile, lpszParams, lpszDir, fsShowCmd)

HWND   hwnd        /* Handle of parent window                          */

LPCSTR lpszOp      /* Address of string for operation to perform       */

LPCSTR lpszFile    /* Address of string for filename                   */

LPCSTR lpszParams  /* Address of string for executable-file parameters */

LPSCTR lpszDir     /* Address of string for default directory          */

int    fsCmdShow   /* Whether file is shown when opened                */

The SpawnAndWait function executes and waits for termination of the

specified application or associated file.

Parameter  Description

-------------------------------------------------------------------------

hwnd       Identifies the parent window. This window receives any message

           boxes an application produces (for example, for error

           reporting).

lpszOp     Points to a null-terminated string specifying the operation to

           perform. This string can be "open" or "print". If this parameter

           is NULL, "open" is the default value.

lpszFile   Points to a null-terminated string specifying the file to

           open.

lpszParams Points to a null-terminated string specifying parameters

           NULL; "open" is the default value. Passed to the application

           when the lpszFile parameter specifies an executable file. If

           lpszFile points to a string specifying a document file, this

           parameter is NULL.

lpszDir    Points to a null-terminated string specifying the default

           directory.

fsShowCmd  Specifies whether the application window is to be shown when

           the application is opened. See ShowWindow for valid values.

Returns

-------

HIWORD == hInstance of started application. Values less than 32 are errors

          returned from ShellExecute. 0xFFFF is a general error.

LOWORD == Return code of spawned application. 0xFFFF is a general error.

Comments

--------

The file specified by the lpszFile parameter can be a document file or an

executable file. If it is a document file, this function opens or prints

it, depending on the value of the lpszOp parameter. If it is an executable

file, this function opens it, even if the string "print" is pointed to by

lpszOp.

WARNING: This function will not wait on applications such as Word and Excel

that respond to the DDE broadcast made by ShellExecute or the second

instance of multiple data applications.

WARNING: This function supports only one block at a time per task. Calling

tasks should not call this function when it has a prior pending

SpawnAndWait call.

Sample Code

-----------

DWORD SpawnAndWaitIndirect(lpSpawnWait)

LPSPAWNWAIT lpSpawnWait /* Far reference to SPAWNWAIT structure

typedef struct tagSPAWNWAIT

{

   HWND   hwnd;

   LPCSTR lpszOp;

   LPCSTR lpszFile;

   LPCSTR lpszParams;

   LPCSTR lpszDir;

   int    fsShowCmd;

   LPMSGPROC lpmsgproc;

} SPAWNWAIT;

Member       Description

----------------------------------------------------------------------

hwnd         Handle of parent window

lpszOp       Address of string for operation to perform

lpszFile     Address of string for filename

lpszParams   Address of string for executable-file parameters

lpszDir      Address of string for default directory

fsShowCmd    Whether file is shown when opened

lpmsgproc    Address of application provided MessagePump (must load

             DS on entry)

void CALLBACK MessagePump(lpmsg)

LPSMG lpsg   /* Long pointer to MSG to process

Message Proc is a place holder for an application-provided callback

function (which must load DS on entry) that will process messages retrieved

in RunLib's PeekMessage loop. It allows the calling application to do

modeless dialog box and accelerator message processing.

lpmsgproc should be set to NULL if it is not used. RunLib will do a default

TranslateMessage/DispatchMessage instead.

The following is an example of a message processing function for a MDI

application:

void CALLBACK MyMessagePump(LPMSG lpmsg)

{

   if(!TranslateMDISysAccel(hClient, lpsmg) &&

      !TranslateAccelerator(hFram, hAccel, lpsmg))

      {

         TranslateMessage(lpsmg);

         DispatchMessage(lpmsg);

      }

}

Returns

-------

HIWORD == hInstance of started application. Values less than 32 are errors

          returned from ShellExecute. 0xFFFF is a general error.

LOWORD == Return code of spawned application. 0xFFFF is a general

          error.

Comments

--------

The file specified by the lpszFile parameter can be a document file or an

executable file. If it is a document file, this function opens or prints

it, depending on the value of the lpszOp parameter. If it is an executable

file, this function opens it, even if the string "print" is pointed to by

lpszOp.

WARNING: This function will not wait on applications such as Word and Excel

that respond to the DDE broadcast made by ShellExecute or the second

instance of multiple data applications.

WARNING: This function supports only one block at a time per task. Calling

tasks should not call this function when it has a prior pending

SpawnAndWait call.

Additional reference words: 3.00 3.10 softlib RUNWAIT.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrToolHlp


SAMPLE: Dialing a Modem in Windows 3.1

Article ID: Q105501

--------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

--------------------------------------------------------------------

DIAL is a sample application that demonstrates how to dial a modem

under Windows 3.1.

Download DIAL.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DIAL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DIAL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DIAL.EXE

Additional reference words: 3.10 softlib DIAL.EXE

KBCategory: kbprg kbfile

KBSubcategory: KrCommapi


SAMPLE: Paging Down in an Owner-Draw Variable List Box

Article ID: Q112640

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1

-----------------------------------------------------------------------

SUMMARY

=======

Using the Microsoft Windows 3.1 SDK, when page down is used in an owner-

draw variable list box, the selection is changed to the last visible item

in the list box (as it should). However, at this point no subsequent page

downs will work.

To address the page-down problem, the owner-draw variable list box is

subclassed. In the subclass procedure, WM_KEYDOWN is processed. When wParam

is VK_NEXT, the PAGE DOWN key was pressed, and the actual paging down is

implemented. The ODVARLB sample shows how to work around this problem.

ODVARLB can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download ODVARLB.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ODVARLB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get ODVARLB.EXE

NOTE: This is not a problem with Win32-based applications.

MORE INFORMATION

================

The steps required for implementing the page down are as follows:

1. Find out how many items exist in the list box. LB_GETCOUNT message can

   be used to get this information:

      // Get maximum number of items in the list box.

      iMaxItems = SendMessage(hWnd,LB_GETCOUNT,0,0L);

2. Find out which item now has the selection; this item will be moved to

   the top of the list box on a page down. This can be done by sending an

   LB_GETCURSEL to the list box:

      // Get the index for the item which is to be at the top.

      iTopIdx    = SendMessage(hWnd,LB_GETCURSEL,0,0L);

3. If the item that has the focus now is the last item in the list then we

   cannot page down further, so just return.

      // If the focus is already on the last item, we have reached

      // the end of the list so just return.

      if (iTopIdx != (iMaxItems -1))

          // Continue we have more work to do.

4. Otherwise, get the height of the list box by calling GetClientRect():

      // Get the client area rectangle of the list box.

       GetClientRect(hWnd, &rc);

5. Then find out how many items will fit in the list box; because this is

   an owner-draw variable list box, some more elaborate calculation is

   necessary. To do this cleanly, a WM_MEASUREITEM message is sent to the

   parent of the list box and WM_MEASUREITEM code calculates the height for

   each of the items one by one. Then the height of each item is

   accumulated and is compared with the list box's height until the last

   item in the current page is located.

      // Get the index for the last visible item in the list

      // box based on the new top item.

      iBottomIdx = GetLBIndex(hWnd,iTopIdx,iMaxItems,rc.bottom);

   The GetLBIndex() function finds the last item that should be visible

   after the page down is completed. Below is the code for GetLBIndex:

     int GetLBIndex(HWND hLB,int iTopIdx,UINT iMaxLBItems, int lbHeight)

     {

         MEASUREITEMSTRUCT mis;

         int ItmHeights = 0;          // Keeps track of total item heights.

         // Set up the measure item structures fields.

         mis.CtlType = ODT_LISTBOX;

         mis.itemID  = iTopIdx;

         while (mis.itemID <= (iMaxLBItems - 1))

            {

            // Get the items measurement, height in particular.

            SendMessage(GetParent(hLB),WM_MEASUREITEM,

                        0, (LPARAM)(LPMEASUREITEMSTRUCT)&mis);

            // Add it to our total height.

            ItmHeights += mis.itemHeight;

            // If the total item height is still less than

            // the list box:

            if (ItmHeights <= lbHeight)

             // Unless we have reached the end of out list.

              if (mis.itemID == (iMaxLBItems - 1))

            // In this case, return the index to the last item in the list.

                 return (mis.itemID);

              else

             // Check the next item, we want to cycle through again.

                 ++mis.itemID ;

            else

             // We have found the last item to be displayed in the list box

             // so return it.

              return (--mis.itemID);

            }

         return (iTopIdx);

     }

6. When the height of the list box is less than or equal to the height of

   an item, the list box displays only one item or part of an item. In this

   situation some special-case handling is required. When the user presses

   the PAGE DOWN key, the next item in the list becomes visible. Below is

   the code used to adjust the top and bottom index for this special case:

      // Special case: When the height of the list box is less than or

      // equal to the height of an item, the list box displays only one

      // item or part of an item at a time. So, when paging down we need

      // to display the next item in the list.

      if (iBottomIdx <= iTopIdx)

         iBottomIdx = ++iTopIdx;

7. Now the item in step 2 (or 6, iTopIdx) is placed at the top of the list

   and the selection (highlighted) is given to the last item, which is the

   item obtained in step 5 (or 6, iBottomIdx). The scroll bar thumb

   position is automatically updated.

      // Move the item that had the focus to the top, then set the

      // selection to the last visible item in the list box.

      SendMessage(hWnd,LB_SETCURSEL,(WPARAM) iBottomIdx, 0L);

      SendMessage(hWnd,LB_SETTOPINDEX,(WPARAM) iTopIdx, 0L);

   NOTE: Just doing this will cause flashing so the painting is turned off

   in the list box until the page down process is complete. Then the entire

   list box is invalidated and the list box window is updated to reflect

   the changes.

      // Turn off all painting to prevent flashing.

      SendMessage(hWnd, WM_SETREDRAW, (WPARAM) FALSE,0L);

      // Move the item that had the focus to the top, then set the

      // focus to the last visible item in the list box.

      SendMessage(hWnd,LB_SETCURSEL,(WPARAM) iBottomIdx, 0L);

      SendMessage(hWnd,LB_SETTOPINDEX,(WPARAM) iTopIdx, 0L);

      // We are done, so turn on painting. Invalidate the list box window

      // for painting and then update the list window.

      SendMessage(hWnd, WM_SETREDRAW, (WPARAM) TRUE,0L);

      InvalidateRect(hWnd,NULL,TRUE);

      UpdateWindow(hWnd);

   However, adding the WM_SETREDRAW messages to eliminate flashing prevents

   the scroll bar from being updated. To address this problem, the scroll

   bar position is retrieved via GetScrollPos() and then reset and painted

   via SetScrollPos().

      pos = GetScrollPos(hWnd,SB_VERT);

      SetScrollPos(hWnd,SB_VERT,pos,TRUE);

   The code for this workaround is the ODLB.C file. All the necessary code

   for this workaround is actually contained in two functions,

      SbListSubProc() - The subclass procedure for the list box.

      GetLBIndex()    - Finds the last visible item in the list box

                        after paging down.

To see the demonstration, select the list box menu item and then page down!

The font on the list box can also be changed using the Change Font menu

option. Changing the font demonstrates how the code works with a different

number of visible items in the list box.

Additional reference words: 3.10 softlib owner draw listbox softlib

ODVARLB.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Using ExtDeviceMode() to Modify Printer Settings

Article ID: Q112641

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

----------------------------------------------------------------------

SUMMARY

=======

The sample program EXTDEV2 demonstrates the correct method for calling

ExtDeviceMode() to change the current printer's orientation to landscape.

The sample code can easily be modified to change other printer settings

such as paper size and print quality. This article discusses the steps

necessary for using ExtDeviceMode() properly and includes the

GetPrinterDC() function, which is used to change paper orientation in the

sample.

EXTDEV2 is based on the PRNTFILE sample from the Windows SDK versions 3.0

and 3.1. EXTDEV2 also corrects a minor bug in the PRNTFILE sample. For

additional information about that bug, please see the following article(s)

in the Microsoft Knowledge Base:

ARTICLE-ID: Q101413

TITLE     : Diagnosing Printing Problems in Your Application

EXTDEV2 can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download EXTDEV2.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EXTDEV2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EXTDEV2.EXE

MORE INFORMATION

================

Beginning with Windows version 3.0, many printer drivers implement a

convention for controlling print settings on a job-by-job basis, without

requiring user intervention via a dialog box. This is accomplished via the

ExtDeviceMode() function as described in Chapter 17 of the Microsoft

Windows SDK "Guide to Programming" for both versions 3.0 and 3.1. The

DeviceCapabilities() function, also introduced in Windows 3.0, provides

information about the print settings supported by a given driver. As of

Windows version 3.1, changes to printer settings are allowed on a page-by-

page basis via the use of the ResetDC() API.

ExtDeviceMode() and DeviceCapabilities() are supplied by the printer

drivers rather than GDI. Because not all drivers support these functions,

applications must ensure that the driver supports these functions before

attempting to use them.

Because of the Universal Printer Driver (UNIDRV), almost all Windows 3.1

printer drivers support these functions. The HP Plotter driver (HPPLOT.DRV)

is a notable exception. The only way to change the settings on the HP

Plotter is to display the driver's print setup dialog box, which is

accomplished by calling the driver's DeviceMode function.

Correct usage of ExtDeviceMode() and DeviceCapabilities() to query and/or

modify printer settings is a multistep process that is not fully explained

in the SDK documentation.

Because these functions reside in the printer driver rather than GDI,

applications must first get a handle to the driver, typically by calling

LoadLibrary(), and then use GetProcAddress() to get the address of the

driver's ExtDeviceMode() and/or DeviceCapabilities() functions. If

GetProcAddress() returns NULL for either of these functions, then that

function is not supported by the driver.

Furthermore, because ExtDeviceMode() and DeviceCapabilities() are not

Windows APIs, they are not prototyped in WINDOWS.H. Instead, function

pointer types are defined for both of these functions in PRINT.H included

in the Windows 3.1 SDK and in DRIVINIT.H included in the Windows 3.0 SDK.

Use LPFNDEVMODE for ExtDeviceMode(); use LPFNDEVCAPS for

DeviceCapabilities(). Using these types is important for compiler type-

checking and ensures that the correct arguments are passed on the stack.

Not using these types (for example, using FARPROC) can lead to general

protection (GP) faults in some circumstances.

PRINT.H (or DRIVINIT.H) also defines the device-independent part of the

DEVMODE structure used for manipulating printer settings. Note that the

DEVMODE structure actually used by a printer driver contains the device-

independent part followed by a driver-specific part that varies in size and

content with each driver and driver version.

Because of this driver-dependence, it is very important for applications to

query the driver for the correct size of the DEVMODE structure before

allocating a buffer for it.

The following code fragment loads a printer driver, calls ExtDeviceMode()

(if supported) to get the full DEVMODE size, and allocates a buffer for the

full DEVMODE structure:

   #include <print.h>            // Formerly DRIVINIT.H in 3.0

   HINSTANCE hDriver;            // Handle to driver

   LPFNDEVMODE ExtDeviceMode;    // Function pointer variable

   PDEVMODE pdm;                 // Pointer to DEVMODE struct

   int nSize;                    // Size of printer's DEVMODE struct

   hDriver = LoadLibrary(szDriver);

   if (hDriver < HINSTANCE_ERROR)

     return;                     // Error

   ExtDeviceMode = (LPFNDEVMODE) GetProcAddress(hDriver, "EXTDEVICEMODE");

   if (!ExtDeviceMode)

     {

     FreeLibrary(hDriver);       // ExtDeviceMode() not supported

     return;

     }

   // Get size of DEVMODE

   nSize = ExtDeviceMode(hWnd, hDriver, NULL, szDevice, szPort,

                         NULL, NULL, 0);

   // Allocate buffer for DEVMODE

   pdm = (PDEVMODE) LocalAlloc(LPTR, nSize);  // check for failure!

Often, it is desirable to query the driver for the current printer

settings. This can be accomplished by allocating a buffer for the DEVMODE

structure as above, and then calling ExtDeviceMode() a second time, passing

the address of the output buffer and using the DM_OUT_BUFFER flag (also

known as DM_COPY). For example:

  ExtDeviceMode(hWnd, hDriver, pdm, szDevice, szPort, NULL, NULL, DM_COPY);

Once the current settings are obtained, applications should use the

dmFields member of the DEVMODE structure to determine which of the

subsequent DEVMODE fields were initialized by the driver. Only fields with

the corresponding bit set in dmFields should be used by the application;

other fields are not supported by the driver.

To change printer settings, the application should not only change the

appropriate fields of DEVMODE, but also indicate which fields were changed

by setting the corresponding bits in dmFields. For example, the following

code fragment sets landscape printing:

   DWORD dwFields;

   ...

   dwFields = pdm->dmFields;     // Save this

   pdm->dmFields = 0             // We haven't changed anything yet

   if (dwFields & DM_ORIENTATION)

     {

     pdm->dmFields |= DM_ORIENTATION;

     pdm->dmOrientation = DMORIENT_LANDSCAPE;

     }

   // Continue changing other settings

A driver may support modifying a certain DEVMODE field without supporting

all of the available settings for that field. For example, an application

cannot use ExtDeviceMode() to switch to Executive paper if the printer only

supports Letter, Legal, and A4 paper sizes. Applications should use

DeviceCapabilities() to query the driver for this type of information. For

an example of using DeviceCapabilities(), please see the following

article(s) in the Microsoft Knowledge Base:

ARTICLE-ID: Q81245

TITLE     : DeviceCapabilities() Function Sample Code

When the application is done modifying DEVMODE, it is necessary to call

ExtDeviceMode() again to allow the driver to merge the new settings and to

update the driver-dependent part of the DEVMODE structure if necessary.

This is done by providing both an input and an output DEVMODE (a single

buffer can be used) and by using both the DM_OUT_BUFFER and DM_IN_BUFFER

(also known as DM_COPY and DM_MODIFY) flags.

   ExtDeviceMode(hWnd, hDriver, pdm, szDevice, szPort,

                 pdm, NULL, DM_IN_BUFFER|DM_OUT_BUFFER);

DEVMODE is now ready for use in CreateDC() or ResetDC() for printing.

Changes made to printer settings in this manner are specific to the

particular print job. It is also possible to change the system-wide default

settings for a printer by using DM_OUT_DEFAULT (also known as DM_UPDATE) in

addition to DM_IN_BUFFER and DM_OUT_BUFFER in the final call to

ExtDeviceMode() above. However, this is discouraged. It is more appropriate

for the user to make changes to default settings through the Control Panel.

The following function from the EXTDEV2 sample demonstrates the above

method for changing the printer orientation to landscape:

Code Sample

-----------

#include <windows.h>

#include <print.h>    // Formerly DRIVINIT.H in 3.0

/**************************************************************************

**

    FUNCTION: GetPrinterDC()

    PURPOSE:  Get hDC for default device according to information in the

              "device" entry in the "windows" section of WIN.INI. Set

              the device context to landscape orientation if supported.

    COMMENTS: Calls ExtDeviceMode() in printer driver to set the device

              context to landscape if supported.

              See the documentation for ExtDeviceMode() and the DEVMODE

              structure for more information.

    RETURNS:  hDC > 0 if success

              hDC = 0 if failure

***************************************************************************

*/

HANDLE GetPrinterDC()

{

    char          pPrintInfo[80];

    LPSTR         lpTemp;

    LPSTR         lpPrintType;

    LPSTR         lpPrintDriver;

    LPSTR         lpPrintPort;

    char          pmodule[32];

    HANDLE        hDriver = 0;

    HANDLE        hDevMode = 0;

    LPDEVMODE     lpDevMode = NULL;

    LPFNDEVMODE   lpfnExtDeviceMode;

    HDC           hDC;

    int           count;

    // Get the default printer information from WIN.INI.

    // The string contains the printer name, driver filename, and port.

    if (!GetProfileString("windows", "Device", (LPSTR)"", pPrintInfo, 80))

        return (NULL);

    // Parse the string we just got from WIN.INI.

    // lpPrintDriver will be the driver filename (for example, HPPCL5MS).

    // lpPrintType will be the printer name (for example, HP Laserjet III).

    // lpPrintPort will be the port (for example, LPT1:).

    lpTemp = lpPrintType = pPrintInfo;

    lpPrintDriver = lpPrintPort = 0;

    while (*lpTemp)

    {

        if (*lpTemp == ',')

        {

            *lpTemp++ = 0;

            while (*lpTemp == ' ')

                lpTemp = AnsiNext(lpTemp);

            if (!lpPrintDriver)

                lpPrintDriver = lpTemp;

            else

            {

                lpPrintPort = lpTemp;

                break;

            }

        }

        else

            lpTemp = AnsiNext(lpTemp);

    }

    // Build driver name

    wsprintf (pmodule, "%s.drv",(LPSTR)lpPrintDriver);

    // Load driver

    if ((hDriver = LoadLibrary(pmodule)) > 31)

    {

        // Get a function pointer to the ExtDeviceMode() function.

        // ExtDeviceMode() resides in the driver so we can't call it

        // directly.

        if (lpfnExtDeviceMode = (LPFNDEVMODE)GetProcAddress(hDriver,

                                               (LPSTR)"EXTDEVICEMODE"))

        {

           // Get the number of bytes in the full DEVMODE buffer.

           // This includes the device-dependent part at the end

           // of the DEVMODE struct.

           count = lpfnExtDeviceMode(0,

                                     hDriver,

                                     NULL,

                                     lpPrintType,

                                     lpPrintPort,

                                     NULL,

                                     NULL,

                                     0);    // 0 = get buffer size

           if (count != -1)

           {

               // Allocate storage for the DEVMODE buffer.

               hDevMode = GlobalAlloc(GHND, count);

               if (hDevMode)

               {

                  lpDevMode = (LPDEVMODE)GlobalLock(hDevMode);

                  // Get the current printer settings.

                  count = lpfnExtDeviceMode(0,

                                            hDriver,

                                            lpDevMode,   // Output buffer

                                            lpPrintType,

                                            lpPrintPort,

                                            NULL,

                                            NULL,

                                            DM_OUT_BUFFER); // aka DM_COPY

                  // Check to see if this printer supports changing

                  // the orientation. You should check dmFields

                  // before changing any printer setting.

                  if (lpDevMode->dmFields & DM_ORIENTATION)

                  {

                     // Pass lpDevMode as both the input and output

                     // DEVMODE buffers. It is important to pass

                     // in the full DEVMODE from the previous call

                     // to ExtDeviceMode() as the input buffer because

                     // it has been completely initialized by the

                     // driver. If you do not do this, the results

                     // are sporadic--sometimes it works and sometimes

                     // it doesn't depending on the printer driver and

                     // the setting you are trying to change.

                     // Zero out all the fields and then set the bit(s)

                     // for the field(s) we want to change.

                     lpDevMode->dmFields = 0;

                     lpDevMode->dmFields = DM_ORIENTATION;

                     // Change to landscape.

                     lpDevMode->dmOrientation = DMORIENT_LANDSCAPE;

                     // Call ExtDeviceMode() once more to allow the driver

                     // to change the device-dependent portion of the

                     // DEVMODE buffer if it needs to.

                     count = lpfnExtDeviceMode(0,

                                             hDriver,

                                             lpDevMode,  //Output buffer

                                             lpPrintType,

                                             lpPrintPort,

                                             lpDevMode,  // Input buffer

                                             NULL,

                                             DM_OUT_BUFFER | DM_IN_BUFFER);

                                             // aka DM_COPY | DM_MODIFY

                     hDC = CreateDC(lpPrintDriver,

                                    lpPrintType,

                                    lpPrintPort,

                                    (void FAR*)lpDevMode);

                  }

                  else

                  {

                     // The printer doesn't support the field you're

                     // trying to change. Just use the current printer

                     // settings.

                     hDC = CreateDC(lpPrintDriver,

                                    lpPrintType,

                                    lpPrintPort,

                                    (void FAR*)lpDevMode);

                  }

                  GlobalUnlock(hDevMode);

                  GlobalFree(hDevMode);

                  FreeLibrary(hDriver);

                  return hDC;

               } // end hDevMode

           }  // end count != -1

        } // end lpfnExtDeviceMode != 0

    } // end hDriver > 31

// If we got here, an error has occurred so finish cleanup and return NULL.

    if (hDriver)

       FreeLibrary(hDriver);

    return NULL;

} // end GetPrinterDC

There are some common variations to the above method when calling

ExtDeviceMode(). For example, if you just want to create a printer HDC

using the current printer settings, you only need to call ExtDeviceMode()

twice, as described above. The first call is to get the size of the full

DEVMODE and the second call is to get the current printer settings. You

then just pass the initialized LPDEVMODE to CreateDC.

ExtDeviceMode() can also be used to display the printer driver's setup

dialog box. Note that this dialog box is driver-specific, and may be

slightly different than the common dialog box's (COMMDLG.DLL) setup dialog

box, which is displayed by calling the PrintDlg function.

To display the driver's setup dialog box with the current printer settings,

you only need to call ExtDeviceMode() twice as describe above but with one

minor change. On the second call to ExtDeviceMode(), use the flags

DM_IN_PROMPT | DM_OUT_BUFFER (also known as DM_PROMPT | DM_COPY). The

DM_IN_PROMPT flag displays the dialog box and the DM_OUT_BUFFER flag copies

the settings from the dialog box into the LPDEVMODE.

You can also display the driver's setup dialog box and change which dialog

box controls are selected when the dialog box is displayed. For example, if

you want to display the printer driver's setup dialog box but have the

dialog box displayed with the landscape control selected, use the above

approach with one minor change. On the third call to ExtDeviceMode(),

specify the flags DM_OUT_BUFFER | DM_IN_BUFFER | DM_IN_PROMPT. DM_IN_BUFFER

initializes the dialog box controls, DM_IN_PROMPT displays the setup dialog

box, and DM_OUT_BUFFER copies the settings from the dialog box into the

LPDEVMODE.

Additional reference words: 3.00 3.10 EXTDEV print gpf gp-fault softlib

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


SAMPLE: Implementing a List Box Full of Dialog Boxes

Article ID: Q113189

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

In some cases, a user interface may require many dialog boxes to be present

at one time. It is possible to display these dialog boxes inside of an

owner-draw list box by moving the dialog boxes over the area that the list

box's items cover.

The LISTDLG sample demonstrates this method of displaying dialog boxes. The

sample uses a fixed height, owner-draw list box with a vertical scroll bar

to display several modeless dialog boxes. The scroll bar can be used to

scroll through the dialog boxes.

LISTDLG can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download LISTDLG.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LISTDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LISTDLG.EXE

MORE INFORMATION

================

This sample demonstrates how to implement an owner-draw list box that

contains a list of modeless dialog boxes. The sample displays a dialog box

containing a list box with the LBS_OWNERDRAWFIXED style. It then creates

five modeless dialog boxes and places five entries in the list box. Then,

the sample associates a dialog box handle for each entry in the list box by

sending an LB_SETITEMDATA message to the list box for each list box entry.

The LISTDLG sample implements an owner-draw list box and shows how to

handle the WM_MEASUREITEM and the WM_DRAWITEM messages associated with the

list box. When a WM_DRAWITEM message is sent to the owner of the list box,

the appropriate modeless dialog box is moved via MoveWindow() to cover the

entire area of the list box item specified in the itemID field of the

DRAWITEMSTRUCT structure. To show which dialog box (list box item) is

currently selected, the WM_CTLCOLOR message is used to change the

background and text color of the dialog boxes. When a dialog box is

currently selected, its background color will be COLOR_HIGHLIGHT and its

text color will be COLOR_HIGHLIGHTTEXT.

The WM_MOUSEACTIVATE, WM_SETFOCUS, and WM_CTLCOLOR messages for the dialog

boxes are all handled by the following three generic functions in the

source file DIALOG.C:

   BOOL HandleMouseActivate(int nIndex, HWND hDlg)

   BOOL HandleSetFocus(int nIndex, HWND hDlg)

   BOOL HandleCtlColor(int nIndex, HWND hDlg, WORD wParam, LONG lParam)

The "nIndex" parameter is the zero-based list box item index associated

with the dialog box and hDlg is a handle to the dialog box. It is important

that all dialog boxes that are associated with the list box call these

functions when processing the above messages.

To select a dialog box from the list box, just click the left mouse button

anywhere on the dialog box, as you would do to select a normal list box

item. You can also scroll through the dialog boxes by using the scroll bar

on the list box. You can move from one dialog box to the next one in line

by choosing the Next button on any dialog box. The focus will scroll around

to the first dialog box in the list when the Next button of the last dialog

box is chosen. It is important that all dialog boxes that are associated

with the list box have a Next button so keyboard mobility is possible.

Additional reference words: 3.10 listbox dialogs scrollbar softlib

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: WFW Named Pipe Client

Article ID: Q113190

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   for Workgroups versions 3.1 and 3.11

----------------------------------------------------------------------

SUMMARY

=======

The file NPCLNT.EXE in the Microsoft Software Library demonstrates the

named pipe client interface in Windows for Workgroups (WFW).

This sample provides a WFW named pipe client for the Win32 SDK named pipe

sample (NPSERVER). This sample opens, reads, and writes to the named pipe

created by the NPSERVER application. The DosReadAsyncNmPipe API is used to

perform asynchronous reads from the server's named pipe to avoid blocking

under WFW.

NOTE: This sample has two problems.

 - The NP callback should be in a fixed code segment in a DLL.

 - Memory passed to DosReadAsyncNmPipe and DosWriteAsyncNmPipe should be

   fixed and pagelocked.

MORE INFORMATION

================

Care must be taken when using DosReadAsyncNmPipe or DosWriteAsyncNmPipe.

Because both APIs provide WFW a function pointer that is called at

interrupt time, only limited operations may be performed in the callback.

The WFW SDK reference states the following about the callback function:

   Generally, the callback function can set global variables and check the

   variable specified by the pusErrCode parameter for potential errors. But

   the callback function must not modify registers or call any MS-DOS

   system functions, BIOS functions, or C run-time functions that call MS-

   DOS and BIOS functions. Although the callback function can call the

   PostMessage function, it must not call the SendMessage function.

Also, the callback function must be exported in the application's *.DEF

file. Besides exporting, the application must call MakeProcInstance on the

function before calling the asynchronous API. Care must also be taken not

to call FreeProcInstance while a read or write is outstanding.

NPCLNT.EXE can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download NPCLNT.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NPCLNT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get NPCLNT.EXE

Additional reference words: WFW Workgroups 3.10 3.11 Named Pipe softlib

NPCLNT.EXE

DosReadAsyncNmPipe DosWriteAsyncNmPipe

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkNmPipe


SAMPLE: Plotting TrueType Characters

Article ID: Q113262

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The HPPLOT plotter driver does not support the plotting of TrueType fonts.

This driver only plots fonts that are native to the plotter or are Windows

vector fonts. It is sometimes desirable to be able to plot a larger range

of fonts. Incorporating the use of TrueType fonts on a plotter greatly

increases the range of fonts a plotter can draw.

The TTPLOT sample demonstrates a method of displaying TrueType fonts on a

plotter. This method involves selecting a TrueType font into a screen

display context and calling the GetGlyphOutline() function to retrieve the

curve data points of a TrueType character in the TrueType font rasterizer's

native format. Then, with the data it retrieved, it performs a series of

MoveTo() and LineTo() calls to draw the TrueType character.

This sample can be used with any printer, and it also demonstrates the new

Windows 3.1 printing functions, SetAbortProc(), StartDoc(), EndDoc(),

StartPage(), and EndPage(). This sample application will not run on a

version of Windows earlier than Windows 3.1.

TTPLOT can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download TTPLOT.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TTPLOT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TTPLOT.EXE

MORE INFORMATION

================

This sample demonstrates how to draw TrueType characters on a plotter with

the MoveTo() and LineTo() functions. First, it retrieves a glyph's curve

data points in the rasterizer's native format by calling GetGlyphOutline()

with GGO_NATIVE specified in the third parameter. It must call this

function twice. The first time the function is called, NULL is placed in

the lpBuffer parameter so the required buffer size to hold the data is

returned. The second time GetGlyphOutline() is called, the native data is

placed in the buffer specified by the lpBuffer parameter.

A glyph outline is returned as a series of contours, each of which can be a

straight line or a quadratic curve. The TTPLOT sample interprets the data

returned from GetGlyphOutline() and then draws the lines specified by

calling the MoveTo() and LineTo() functions on the plotter device context.

The quadratic curves, as well as the lines, are both drawn as normal

straight lines. A description of this native curve data can be found on

pages 382-383 of the Windows SDK "Programmer's reference, Volume 2:

Functions" manual or by searching for the GetGlyphOutline() function in the

"Win31 Help" Windows help file. This sample also lets you choose a desired

TrueType font by bringing up the ChooseFont() common dialog box. Before

drawing the font, the plotter DC is placed in the MM_ISOTROPIC mode so the

fonts will be the same size on the screen as they are on the plotter.

Additional reference words: 3.10 PLOT HPPLOT TRUETYPE softlib TTPLOT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiPrn


SAMPLE: Troubleshooting Guide for the 16-bit Setup Toolkit

Article ID: Q114603

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

STPHLP.EXE contains a Microsoft Windows 3.1 Help file containing the

answers to the most frequently asked questions about the Microsoft Windows

3.1 SDK Setup Toolkit. The help file contains a list of bugs and

workarounds, samples for implementing commonly requested features, and

short tutorials for commonly confusing issues.

STPHLP.EXE can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download STPHLP.EXE

      -or-

      GO WINSDK and download STPHLP.ZIP

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download STPHLP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get STPHLP.EXE

KBCategory: kbtool kbsetup kbfile

KBSubcategory: TlsMss

Additional reference words: 3.10 mssetup toolkit setup softlib STPHLP.EXE


SAMPLE: Open Multiple AVIs, Use of MCI_PUT Command

Article ID: Q115566

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The AVIWIN sample demonstrates how you can open and close AVI files in the

background while playing another AVI file. This sample also demonstrates

the MCI_WINDOW and MCI_PUT commands.

NOTE: The Open command takes 1 to 2 seconds to complete. On slower

machines, the playback of one AVI is slightly disrupted if you try to open

another AVI file in the background. This disruption might cause some video

frames to be dropped or skipped.

When you run the AVIWIN.EXE file, remember that you can only play an AVI if

you have already opened it. The menu items are always enabled, even when

the command should not be run. For example, the Play menu commands are

always enabled, even when the MCI_PLAY command would fail. If you try to

play an AVI before you open it, you get the following message box:

   Reminder: Did you Open the first/second AVI? [Yes] [No]

If you click "Yes," you see the error message that returned from the

mciSendCommand() function. If you click "No," the focus returns to the

AVIWIN.EXE file, and you are then able to open an AVI file.

MORE INFORMATION

================

This sample was written in Microsoft Visual C++ version 1.5. The source

files of the AVIWIN are listed below and are contained in the archive file

AVIWIN.EXE.

   ABOUT.C

   AVIWIN.C

   AVIWIN.DEF

   AVIWIN.H

   AVIWIN.MAK

   AVIWIN.RC

   DIGITALV.H

   README.TXT

   RESOURCE.H

Download AVIWIN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for AVIWIN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download AVIWIN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get AVIWIN.EXE

Additional reference words: 3.10 MCI_PUT MCI_WINDOW softlib AVIWIN.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMVideo


SAMPLE: SPINDIB Demonstrates 90-degree DIB Rotation

Article ID: Q115761

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

----------------------------------------------------------------------

SPINDIB demonstrates how to perform 90-degree rotation on a device-

independent bitmap (DIB). SPINDIB supports 1-bit-per-pixel (BPP), 4-BPP,

and 8-BPP DIB rotation. This sample also demonstrates how to flip and/or

mirror an image using StretchBlt/StretchDIBits.

Download SPINDIB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SPINDIB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SPINDIB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SPINDIB.EXE

Additional reference words: 3.10 softlib SPINDIB.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmpRotate


SAMPLE: Using MCI Commands in Visual Basic

Article ID: Q116082

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

 - Microsoft Video for Windows Development Kit, version 1.1

 - Microsoft Visual Basic for Windows, version 3.0

----------------------------------------------------------------------

SUMMARY

=======

The VBMCI sample shows how to use the function "mciSendString()" in

Microsoft Visual Basic to play multimedia files. This sample also uses the

custom control "MMControl" from the MCI.VBX custom-control file to play

multimedia files. You may find it easier to use MMControl to manipulate

multimedia files than to use mciSendString() commands.

MORE INFORMATION

================

This sample demonstrates only a few of the features of MMControl and a few

of the commands strings that mciSendString() can use. The "Microsoft Visual

Basic Professional Features," Book 1, contains a complete description of

all of the features of MMControl.

The following files are included in the file VBMCI.EXE:

   FORM1.FRM

   FRMABOUT.FRM

   GLOBAL.BAS

   MCIVBX.FRM

   OPENDLG.FRM

   README.TXT

   VBMCISTR.MAK

Download VBMCI.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for VBMCI.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download VBMCI.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get VBMCI.EXE

REFERENCES

==========

You can find more information on command strings that you can send by using

mciSendString() in the following resources:

 - "Multimedia Programmer's Reference," included with the Windows 3.1

   Software Development Kit (SDK).

 - "Multimedia Programmer's Guide," included with the Windows 3.1 SDK.

 - MCISTRWH.HLP, a Windows Help file included with Microsoft Visual C++,

   Professional Edition, version 1.X.

 - DK_DOC.MVB or DK_DOC.HLP, Windows Help files included with the Video for

   Windows Development Kit, version 1.1. (NOTE: These Help files also

   contain information on the controls in the MCI.VBX and MCIWNDX.VBX

   custom-control files.)

The "Microsoft Video for Windows Development Kit," version 1.1, comes with

a robust sample of how to use the features of the custom-control file

MCIWNDX.VBX. This sample is called "VBMCITst".

In addition, there is a helpful topic in both the DK_DOC.HLP and DK_DOC.MVB

files titled "Comparing MCIWNDX.VBX to MCI.VBX".

Additional reference words: 3.10 1.10 3.00 softlib VBMCI.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMMisc


SAMPLE: Direct-to-Disk Recorder with ACM

Article ID: Q116293

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

DDREC is a sample that shows how to use the low-level multimedia

application programming interface (API) to perform direct-to-disk recording

of sound using real-time audio compression from an application for Windows

written in the C language.

Download DDREC.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DDREC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DDREC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DDREC.EXE

MORE INFORMATION

================

The Windows MCI commands may be used to record wave audio data from within

an application. However, MCI is implemented as a high-level interface. This

implementation does not provide extensive control over the recording

process, and does not provide easy access to the recorded data.

For more control over data access and the recording process, the low-level

multimedia API may be used. If you know ahead of time how much memory will

be required for the entire recording, and you know that the required amount

is available, you may use a simple one-shot recording procedure (ie: memory

allocate, open device, record, close device). In the wave audio recording

world, huge memory requirements are common and this process may not be be

applicable.

If, however, you do not know the total recording, and/or you want to keep

memory requirements to a minimum, a direct-to-disk process may be

desirable. This is also known as a double buffer approach, which repeats

the process of writing one filled buffer to a disk file while recording

another.

DDREC uses two buffers of approximately 32K each that are locally allocated

at program startup. When the record process is initiated, the wave buffers

are added to the input queue and recording begins. When the first buffer is

filled, it is written to a temporary file while the second buffer is

filled. After the buffer is written the buffer is queued to for wave audio

input again. This procedure is repeated for each buffer until the user

stops the recording.

DDREC shows how to use these same two buffers for playing the audio as well

as recording using a similar double buffer approach. It also uses the

multimedia input/output (mmio*) procedures for reading and saving the wave

data in a .WAV format RIFF file.

DDREC also implements the WAVEFORMATEX structure for handling other wave

formats besides PCM. It handles compressed formats auomatically using

function calls to the Audio Compresison Manager (ACM).

Additional reference words: 3.10 softlib DDREC.EXE

KBCategory: kbmm kbprg kbfile

KBSubcategory: MMWave


SAMPLE: Multimedia Registration Kit revision 3.0

Article ID: Q120253

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

----------------------------------------------------------------------

SUMMARY

=======

The Multimedia Registration Packet (MDRK.EXE) is a collection of updated

documents that developers can use for help in writing multimedia

applications for the Windows environment,

Download MDRK.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MDRK.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MDRK.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get MDRK.EXE

MORE INFORMATION

================

The packet includes Microsoft Word and ASCII text versions of the following

files:

MMREG Multimedia Registration Kit

---------------------------------

This kit enables a developer to register new formats and product IDs with

Microsoft for the purpose of providing support for the format by other

developers.

MSFTMM Multimedia Document Overview

-----------------------------------

This document provides a list of the current documents available from the

Multimedia Technologies group at Microsoft.

RIFFNEW Multimedia Data Types and Techniques

--------------------------------------------

This document provides a comprehensive description of available multimedia

data types including Resource Interchange File Format (RIFF) and wave

types.

PROD_IDS New Multimedia IDs

---------------------------

This is a complete list of registered manufacturer's and their registered

products.

MMREG.H

-------

This header file contains multimedia data types and product IDs that you

can include in the source code of a multimedia C program.

Additional reference words: REGISTRATION MULTIMEDIA RIFF RIFFNEW 3.10

KBCategory: kbmm kbfile kbtool kbprg

KBSubcategory: MMMisc


SAMPLE: SNDPLAY Sample Plays a Sound File

Article ID: Q121208

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

SNDPLAY.EXE is a self-extracting file that contains all files necessary to

build the SNDPLAY program that demonstrates a simple application that plays

a sound file specified on the command line. It displays an error message if

no sound file was specified in the command line or the specified sound

could not be played, and immediately exits whether the sound is played

or not.

Download SNDPLAY.EXE a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SNDPLAY.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SNDPLAY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SNDPLAY.EXE

Additional reference words: 3.10 sndPlaySound softlib

KBCategory: kbmm kbfile kbcode kbtool

KBSubcategory: MMWave


SAMPLE: MIDIIO Sample Demonstrates MIDI Input and Output

Article ID: Q121209

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

MIDIIO.EXE is a self-extracting file that contains all the source files

necessary to build a sample application to demonstrate an implementation of

MIDI device selection and sharing techniques along with simple MIDI data

input and output.

Download MIDIIO.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MIDIIO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MIDIIO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get MIDIIO.EXE

MORE INFORMATION

================

MIDIIO allows viewing of MIDI input messages in raw form or with text

descriptions. MIDI messages can be sent using the mouse or from dialog

controls. MIDI input and output devices are selected from the application

menu. Multiple instances of MIDIIO can be run to demonstrate MIDI device

sharing between applications. Wrapper functions encapsulate low-level MIDI

APIs, handle errors, and simplify application code. Macros are provided for

building MIDI messages to be sent by calling midiOutShortMsg().

Additional reference words: 3.10 MIDIIO.EXE MIDI

KBCategory: kbmm kbfile kbcode

KBSubcategory: MMMidi


SAMPLE: MIDISX.EXE Demos MIDI System Exclusive Communication

Article ID: Q121210

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

---------------------------------------------------------------------

SUMMARY

=======

MIDISX.EXE is a self-extracting file that contains all the source code you

need to build a sample application that demonstrates how to implement MIDI

device sharing techniques and how to process MIDI system exclusive

messages.

Download MIDISX.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MIDISX.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MIDISX.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get MIDISX.EXE

MORE INFORMATION

================

The MIDISX application allows the user to edit a system exclusive message

and transmit it to another MIDI device. The application can receive,

display, and save to disk up to 64K of returned system exclusive data. MIDI

input and output devices are selected from the application menu, and the

application implements techniques that allow it to share MIDI devices with

other applications. Wrapper functions encapsulate low-level MIDI APIs,

handle errors, and simplify application code.

Additional reference words: 3.10 MIDISX.EXE MIDI

KBCategory: kbmm kbfile kbcode

KBSubcategory: MMMidi


SAMPLE: Reading and Writing Aldus Placeable Metafiles

Article ID: Q129658

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

----------------------------------------------------------------------

Windows applications such as Microsoft Word and Microsoft Excel, read and

write metafiles in a format known as Aldus Placeable Format. This format is

incompatible with the Windows GetMetaFile(), CopyMetaFile(), and

PlayMetaFile() functions. This incompatibility occurs because placeable

metafiles begin with a 22-byte header.

Sample code is available in the Microsoft Software Library that you can use

to read and write these placeable metafiles.

Download WMFAPMF.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WMFAPMF.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WMFAPMF.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WMFAPMF.EXE

Additional reference words: 3.10 OpenClipBoard GetClipBoardData

CF_METAFILEPICT

KBCategory: kbgraphic kbfile

KBSubcategory: GdiMeta